Обычно признается, что расширение реализации интерфейса посредством наследования не является лучшей практикой, и что композиция (например, повторная реализация интерфейса с нуля) более удобна в сопровождении.
Это работает, потому что контракт интерфейса заставляет пользователя реализовать все желаемые функции. Однако в java 8 методы по умолчанию обеспечивают некоторое поведение по умолчанию, которое можно переопределить «вручную». Рассмотрим следующий пример: я хочу создать пользовательскую базу данных, которая должна иметь функциональные возможности списка. Я решил, в целях эффективности, поддержать его ArrayList.
public class UserDatabase extends ArrayList<User>{}
Обычно это не считается хорошей практикой, и было бы предпочтительнее, если бы на самом деле желали использовать все возможности списка и следовали обычному девизу «композиция вместо наследования»:
public class UserDatabase implements List<User>{
//implementation here, using an ArrayList type field, or decorator pattern, etc.
}
Однако, если не обращать внимания, некоторые методы, такие как spliterator(), не потребуется переопределять, так как они являются методами интерфейса List по умолчанию. Загвоздка в том, что метод spliterator() в List работает намного хуже, чем метод spliterator() в ArrayList, оптимизированный для конкретной структуры ArrayList.
Это заставляет разработчика
- имейте в виду, что ArrayList имеет свою собственную, более эффективную реализацию spliterator(), и вручную переопределяет метод spliterator() своей собственной реализации List или
- потерять огромное количество производительности, используя метод по умолчанию.
Итак, вопрос: остается ли «верным» то, что в таких ситуациях следует предпочесть композицию наследованию?
public class UserDatabase{ List<User> aList = new ArrayList<>(); //Other code}
- person Blip   schedule 06.07.2015ArrayList
сплитератор. - person Tagir Valeev   schedule 06.07.2015ArrayList
имеет более быструю реализациюsplititerator
, влияет на ваше решение сделать выбор между композицией и наследованием? Какое отношение детали реализации имеют к выбору между наследованием и композицией? Какое отношениеdefault
методов имеет к выбору между ними? Полагаясь на детали реализации для выбора композиции, вы, в первую очередь, бросаете вызов самой цели композиции. Не путайте себя. Держи это просто глупо. - person CKing   schedule 06.07.2015ArrayList
, почему нельзя делегировать методspliterator()
UserDatabase
методуspliterator()
базовогоArrayList
? - person Brian Goetz   schedule 06.07.2015default
был добавлен после код делегирования был написан. Таким образом,spliterator()
— это только пример для обсуждения шаблона проектирования в целом. - person Holger   schedule 07.07.2015