Композиция и наследование в Java — в чём разница? | OTUS

Композиция и наследование в Java — в чём разница?

Java_Deep_6.3-5020-aac927.png

Мы знаем, что и наследование, и композиция, дают нам возможность повторно использовать код на Java. Однако делают они это по-разному. Об этом и поговорим.

Главное отличие между композицией и наследованием заключается в том, что композиция даёт возможность переиспользовать код без расширения существующего класса, как это происходит в случае с наследованием. Не менее важно и то, что композиция позволяет нам выполнять повторное использование кода даже из final-класса, в то время как унаследоваться от него мы не сможем. Есть и ещё кое-что: при композиции допускается использование кода из нескольких разных классов, а вот с наследованием это не сработает, ведь в языке программирования Java множественное наследование не поддерживается (правда, мы можем это сделать в C++).

Таким образом, в Java рекомендуется использовать преимущественно композицию, а не наследование. Почему? Ну, во-первых, это советует Джошуа Блох в книге «Effective Java». Книга, кстати, представляет собой прекрасный источник полезных рекомендаций для Java-разработчика. Во-вторых, ряд убедительных аргументов представлен в статье «5 Reasons to Use Composition over Inheritance in Java and OOP» (рекомендуется к прочтению).

Композиция и наследования: пробуем разобраться

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

Гибкость

Одно из первых отличий связано с гибкостью кода. Используя наследование, мы должны описывать, какой класс расширяем, причём мы не сможем заменить его в процессе выполнения программы. Иначе обстоит дело с композицией: мы можем определить используемый тип, а он, в свою очередь, может включать несколько разных реализаций. В результате композиция предоставляет нам больше гибкости.

Ограниченное повторное применение кода при наследовании

Мы уже упомянули, что унаследоваться в Java возможно лишь от одного класса, т. е. мы можем повторно использовать только один класс. Если же нам нужна функциональность нескольких классов, необходимо использовать композицию. Например, если код должен использовать аутентификацию, то нужно унаследовать класс Authenificator, а при авторизации — Autorizer и т. п. Но т. к. множественное наследование не поддерживается, нам опять остаётся композиция.

Юнит-тесты

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

Final-классы

Очередное ограничение наследования — нельзя расширить final-классы. В языке программирования Java отсутствует возможность унаследования от final-классов, в результате чего мы опять приходим к тому, что для повторного использования кода больше подходит композиция.

Инкапсуляция

Теперь поговорим об отношении композиции и наследования к инкапсуляции. С одной стороны, можно сказать, что обе техники дают возможность повторно использовать код. Так-то оно так, но наследование нарушает принцип инкапсуляции, и всё дело в том, что подкласс имеет зависимость от поведения класса-родителя. Если же родительский класс поменяет свой поведение, это отразится и на его потомках. Например, если классы будут плохо документированы, а класс-потомок будет неправильно использовать родительский класс, при любом изменении класса-родителя функциональность потомка будет поломана. Об этом, кстати, можно почитать в уже упомянутой выше книге «Effective Java», в главах 16 и 17.

comp_inh_1-20219-8c189f.png

Послесловие

Пожалуй, это всё, что хотелось бы рассказать об отличиях наследования и композиции. Да, обе техники служат одной цели — для повторного применения протестированных и проверенных участков Java-кода. Только вот делают они это по-разному. Композиция даёт нам возможность защитить повторно используемый класс от клиентов, в то время как наследование это не гарантирует. Но несмотря на это, в некоторых случаях наследование просто необходимо. Например, если вы создаёте классы из одного семейства.

Источник — «Difference between Inheritance and Composition in Java OOPS».

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто