
Такой объект как «телевизор» в элементарном виде не существует, он состоит из частей, которые, в свою очередь, также состоят из частей. Так вот набор этих конкретных частей мы и называем «телевизор».
В абстракции нужно выносить только те характеристики, без которых в рамках решения конкретной задачи объект не может существовать. Т.е. если характеристика либо может существовать, либо может не существовать, то в абстракцию она не выносится.
Для примера можно взять задачу «избавиться от мышей». Как будем избавляться? С помощью кота, конечно. Что нам важно? Чтобы кот умел ловить мышей. Нам важно какой он породы? Нет. Нам важно как он мурлычет? Нет. Нам важно сколько у него ног? Да по сути нет, если он может ловить мышей. Так вот это качество «ловить мышей» мы и вынесем в абстракцию для решения нашей задачи.
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);
Т.о. абстракция позволяет не зависеть от конкретной реализации!