Абстракция

Абстракция

Абстракция – формирование собирательных понятий. Другое определение - работа только со значимыми характеристиками. Суть этого принципа в том, чтобы разделить составные объекты на их элементарные составляющие. Такой подход позволяет работать непосредственно с объектом, не вдаваясь в подробности, из чего же он состоит и как работает.

Такой объект как «телевизор» в элементарном виде не существует, он состоит из частей, которые, в свою очередь, также состоят из частей. Так вот набор этих конкретных частей мы и называем «телевизор».

В абстракции нужно выносить только те характеристики, без которых в рамках решения конкретной задачи объект не может существовать. Т.е. если характеристика либо может существовать, либо может не существовать, то в абстракцию она не выносится.

Для примера можно взять задачу «избавиться от мышей». Как будем избавляться? С помощью кота, конечно. Что нам важно? Чтобы кот умел ловить мышей. Нам важно какой он породы? Нет. Нам важно как он мурлычет? Нет. Нам важно сколько у него ног? Да по сути нет, если он может ловить мышей. Так вот это качество «ловить мышей» мы и вынесем в абстракцию для решения нашей задачи.


abstract class Cat {
	abstract void doCatch();
}

class Mursic extends Cat {
	String name = "Mursic";
	@Override
	void doCatch() {
		// some code
	} 
}

class Barsic extends Cat {
	String name = "Barsic";
	@Override
	void doCatch() {
		// some code
	} 
}
Теперь создадим класс «Дом» с методом «избавиться от мышей», который будет принимать нашего кота.


class VillageHouse {

	static void catchMice(Cat cat) {
		cat.doCatch();
	}
}
Поскольку метод catchMice() принимает объект типа Cat, то мы можем передать ему любого кота, ведь у любого наследника Cat гарантированно есть метод doCatch(). Так что для catchMice() абсолютно не важно как зовут этого кота или какого он окраса. И всё это благодаря тому, что мы вынесли понятие «Кот» в абстракцию.

Но что если мы захотим избавиться от мышей другим способом? Например, какой-нибудь ультра-современной мышеловкой. Но мы не можем передать в catchMice() мышеловку, т.к. он принимает только котов. Как быть? Отнаследовать мышеловку от кота! Я вас умоляю, не надо так (с). Если захотите уничтожить мышей ядом, его тоже будете от кота наследовать? На этот случай я для себя завела правило: не наследуй виджет температуры от градусника.

Создадим следующий уровень абстракции «Ловящий» и перенесём doCatch() туда:


interface Catchable {
	void doCatch();
}
И вот теперь этот интерфейс может реализовать кто угодно: хоть кот, хоть мышеловка, хоть сачок для бабочек или зеркало для солнечных зайчиков.


abstract class Cat implements Catchable {}


class MouseTrap implements Catchable {
	@Override
	public void doCatch() {
		System.out.println("Clap!");
	} 
}


class VillageHouse {
	static void catchMice(Catchable catcher) {
		catcher.doCatch();
	}
}
И в итоге:


Mursic mursic = new Mursic();
Cat barsic = new Barsic();
Catchable mouseTrap = new MouseTrap();

// избавляемся от мышей любым удобным способом
VillageHouse.catchMice(mursic);
VillageHouse.catchMice(barsic);
VillageHouse.catchMice(mouseTrap);
Т.о. абстракция позволяет не зависеть от конкретной реализации!
ООП РАЗМЫШЛЕНИЯ