Размер шрифта
-
+

Введение в объектно-ориентированный дизайн с Java - стр. 24

Скажем, вы проектируете ресторан пиццы. И вам нужно смоделировать все различные варианты пиццы, которые есть у ресторана в меню.

Учитывая различную комбинацию начинок и названий, которые вы можете использовать для пиццы, может возникнуть соблазн разработать систему, использующую наследование.



И класс пиццы может обобщен.

Это кажется разумным, но давайте посмотрим, почему это является неправильным использованием наследования.

Несмотря на то, что пицца pepperoni – более специфическая пицца, она не очень отличается от суперкласса.

Вы можете видеть, что конструктор pepperoni использует конструктор пиццы и добавляет начинки, используя метод суперкласса.

В этом случае нет причин для использования наследования, потому что вы можете просто использовать только класс пиццы для создания пиццы с пепперони в качестве верхней части.

Второй признак ненадлежащего использования обобщения – если вы нарушаете Принцип Замещения Лискова.

Принцип гласит, что подкласс может заменить суперкласс, тогда и только тогда, когда подкласс не изменяет функциональность суперкласса.

Как этот принцип может быть нарушен через наследование?



Давайте посмотрим на этот пример.

Это наш обобщенный класс животных, и он знает, как есть, гулять и бегать.

Теперь, как мы можем ввести подкласс, который нарушит принцип замещения Лискова?



Что, если у нас есть этот тип животных?

Кит не знает, как гулять и бегать.

Гулять и бегать – это поведение наземных животных.

И принцип замещения Лискова здесь нарушен, потому что класс китов переопределяет класс животных, и ходячие функции заменяет на плавательные функции.

Пример плохого наследования можно увидеть и в библиотеке коллекций Java.

Вы когда-нибудь использовали класс стека в Java?

Стек имеет небольшое количество четко определенных поведений, таких как peak, pop и push.

Но класс стека наследуется от класса вектора.

Это означает, что класс стека может возвращать элемент по указанному индексу, извлекать индекс элемента и даже вставлять элемент по определенному индексу.

И это не является поведением стека, но из-за плохого использования наследования это поведение разрешено.

Если наследование не соответствует вашим потребностям, подумайте, подходит ли декомпозиция.

Смартфон – это хороший пример того, где декомпозиция работает лучше, чем наследование.

Смартфон имеет характеристики телефона и камеры.

И для нас не имеет смысла наследовать от телефона, а затем добавлять методы камеры в подкласс смартфон.

Здесь мы должны использовать декомпозицию для извлечения ответственностей камеры и размещения их в классе смартфона.

Страница 24