Использовать композицию над наследованием

Благодарить композицию над наследованием

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

используйте наследование при наличии чистой связи IS-A между classами.

Пример из этой статьи :

Здесь между Apple и Fruit существует четкая связь IS-A, т.е. Apple IS-A Fruit, но автор также показал ее как Apple HAS-A Fruit (композиция), чтобы показать ловушку, когда она реализована с наследованием.

Я несколько смутился здесь, что в чем смысл высказывания

используйте наследование при наличии чистой связи IS-A между classами.

Использует ли использование композиции над наследованием, что всегда пытается применить композицию, даже если есть чистая связь IS-A и оставить наследование только для тех случаев, когда состав не имеет смысла ?

Когда вы используете наследование для повторного использования кода из суперclassа, а не для переопределения методов и определения другого полиморфного поведения, это часто указывает на то, что вы должны использовать композицию вместо наследования.

Класс java.util.Properties является хорошим примером плохого использования наследования. Вместо использования Hashtable для хранения своих свойств он расширяет Hashtable, чтобы повторно использовать его методы и избегать переопределения некоторых из них с помощью делегирования.

Я думаю, что это один из наиболее обсуждаемых вопросов в объектно-ориентированном дизайне. Как было предложено в статье, композиция всегда предпочтительна по сравнению с наследованием. Это не означает, что вы никогда не должны использовать наследование. Вы должны там, где это имеет больше смысла (что может быть спорным).

Есть много преимуществ использования композиции, пара из которых:

  • У вас будет полный контроль над вашими реализациями. т.е. вы можете выставлять только те методы, которые вы намерены открыть.
  • любые изменения в суперclassе могут быть экранированы путем изменения только в вашем classе. Любые classы клиентов, которые используют ваши classы, не должны вносить изменения.
  • Позволяет вам контролировать, когда вы хотите загрузить суперclass (ленивая загрузка)

В этой статье нет такой фразы:

use inheritance when there is pure IS-A relationship between classes

Более того, Google не нашел его в другом месте, кроме вашего сообщения.

Вместо этого в статье говорится:

Make sure inheritance models the is-a relationship. My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.

Это означает, что если есть связь IS_A, попробуйте сначала использовать наследование, а не состав. И нет предпочтения using composition over inheritance – каждый из них хорош для своей собственной роли.

Кроме того, я хотел бы добавить, что шаблон Decorator является примером, где вы можете использовать композицию над наследованием и динамически добавлять обязанности к объектам. Пример шаблона Decorator упоминается в «Эффективной Java» в элементе «Favor Composition over Inheritance». Принять пример из Java API; BufferedReader украшает Reader (вместо расширения FileReader, PipedReader, FilterReader и т. Д.) И, следовательно, имеет возможность украшать любой вид Reader. Функциональность буферизации прилагается к этим читателям во время выполнения, которое является шаблоном Decorator.

Здесь расширение путем подclassификации было бы непрактичным.

Я думаю, что хорошим ориентиром будет:

Когда есть отношение IS-A, используйте наследование. В противном случае используйте композицию.

Причина этого связана с другой концепцией в объектно-ориентированном дизайне – polymorphismе. Полиморфизм является особенностью многих языков ООП, где объект может использоваться вместо другого объекта при условии, что class первого является подclassом второго.

Чтобы проиллюстрировать, представьте, есть ли у вас функция, которая принимает тип животного. Когда вы используете наследование, у вас есть только одна функция:

 void feed( Animal a ); 

Полиморфизм заверяет нас, что любой подclass животного, который мы положили, будет принят. В противном случае мы будем вынуждены написать одну функцию для каждого типа. Я думаю, что преимущества этого перевешивают его недостатки (например, сокращение инкапсуляции).

Если нет отношения IS-A, я думаю, что polymorphism не будет очень эффективным. Поэтому было бы лучше использовать композицию и улучшать инкапсуляцию / изоляцию между classами.

Используйте наследование, когда отношения постоянны. Не используйте расширение, чтобы получить свободное поведение. Это то, на что они ссылаются в примере IS-A. Расширяйтесь только в том случае, если расширяющийся class действительно является расширением родителя. Будут моменты, когда это не вырезано и сухо, но в целом. Композиция обеспечивает гибкость в будущем, если вам нужно перейти от «правого» classа.

Это старая, но отличная статья о расширении:

http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html

Я бы сказал, нет. В сценарии «фрукты / яблоко» имеет смысл использовать наследование. Автор статьи также подтверждает это: «В приведенном выше примере Apple, вероятно, является« Плодом », поэтому я бы склонен использовать наследование».

Если ваш подclass явно является суперclassом, наследование прекрасное. На практике, однако, вы найдете гораздо больше ситуаций, которые лучше решаются с использованием композиции.

  • Можно ли явно указать параметры шаблона конструктора?
  • c ++ шаблон и файлы заголовков
  • Специализация шаблона на основе classа inherit
  • Каковы некоторые параметры шаблона шаблона?
  • Поддерживает ли C ++ счетчики времени компиляции?
  • WPF: как настроить SelectionBoxItem в ComboBox
  • Совместимость шаблонов с несколькими типами Scala
  • Обходное решение для вывода аргумента шаблона в невыводимом контексте
  • Неопределенная эталонная ошибка для метода шаблона
  • Конструктор шаблонов C ++
  • Какие шаблоны проектирования могут быть применены к проблеме настроек конфигурации?
  • Interesting Posts

    MongoDB: Объедините данные из нескольких коллекций в один … как?

    Rsync: не удалось установить время на "<dir path>"

    Как протрите карту microSD, на которую я не могу писать?

    While-loop игнорирует scanf во второй раз

    Рекомендации по управлению версиями Maven

    Зебра разбивает таблицу со скрытыми строками с помощью CSS3?

    Могу ли я зависеть от значений GetHashCode (), чтобы они были согласованными?

    Создание столбцов из факторов и подсчета

    Как правильно добавить шестнадцатеричные escape-последовательности в строковый литерал?

    Установите приложения тихо, с предоставленным разрешением INSTALL_PACKAGES

    Разница между запуском и запуском нити

    Имеет ли ключевое слово «изменчивое» какие-либо цели, кроме возможности изменять переменную функцией const?

    iphone facebook side menu с помощью объектива c

    Как я могу создать криптографически безопасное псевдослучайное число в C #?

    Могу ли я исправить ошибку 0xc0000225 без переустановки Windows?

    Давайте будем гением компьютера.