Технически все, что может быть реализовано с помощью наследования, может быть реализовано и с делегированием. Таким образом, ответ будет «нет».
Преобразование наследования в делегирование
Допустим, у нас есть следующие классы, реализованные с наследованием:
public class A {
String a = "A";
void doSomething() { .... }
void getDisplayName() { return a }
void printName { System.out.println( this.getDisplayName() };
}
public class B extends A {
String b = "B";
void getDisplayName() { return a + " " + b; }
void doSomething() { super.doSomething() ; ... }
}
Все работает хорошо, и вызов printName
для экземпляра B приведет к выводу "A B"
в консоли.
Теперь, если мы переписаем это с делегированием, мы получим:
public class A {
String a = "A";
void doSomething() { .... }
void getDisplayName() { return a }
void printName { System.out.println( this.getName() };
}
public class B {
String b = "B";
A delegate = new A();
void getDisplayName() { return delegate.a + " " + b; }
void doSomething() { delegate.doSomething() ; ... }
void printName() { delegate.printName() ; ... }
}
Нам нужно определить printName
в B, а также создать делегат при создании экземпляра B. Вызов doSomething
будет работать так же, как и при наследовании. Но вызов printName
напечатает "A"
в консоли. Действительно, с делегированием мы утратили мощную концепцию «this», связанную с экземпляром объекта, и базовые методы могли вызывать методы, которые должны быть переопределены.
Это может быть решено в языке поддерживает чистое делегирование. При чисто делегировании «this» в делегате будет по-прежнему ссылаться на экземпляр B. Это означает, что this.getName()
запустит диспетчеризацию метода из класса B. Мы достигаем того же, что и с наследованием. Этот механизм используется в основанном на прототипах языке , таком как Self , у которого есть делегирование, имеет встроенную функцию ( здесь , как наследование работает в Self, вы можете прочитать ).
Но у Java нет чистого делегирования. Когда тогда застрял? Нет, правда, мы все еще можем сделать это сами, приложив еще больше усилий:
public class A implements AInterface {
String a = "A";
AInterface owner; // replace "this"
A ( AInterface o ) { owner = o }
void doSomething() { .... }
void getDisplayName() { return a }
void printName { System.out.println( owner.getName() };
}
public class B implements AInterface {
String b = "B";
A delegate = new A( this );
void getDisplayName() { return delegate.a + " " + b; }
void doSomething() { delegate.doSomething() ; ... }
void printName() { delegate.printName() ; ... }
}
Мы в основном заново реализуем то, что обеспечивает встроенное наследование. Имеет ли это смысл? Нет, правда. Но это показывает, что наследование всегда можно преобразовать в делегирование.
Обсуждение
Наследование характеризуется тем, что базовый класс может вызывать метод, который переопределяется в подклассе. Это, например, суть шаблона шаблона . Такие вещи не могут быть легко сделаны с делегированием. С другой стороны, именно это затрудняет использование наследования. Требуется умственный поворот, чтобы понять, где происходят полиморфные изменения и каков эффект, если методы переопределены.
Есть некоторые известные подводные камни о наследовании и хрупкости 1046 *, которые он может внести в дизайн. Особенно, если иерархия классов развивается. Также могут быть некоторые проблемы с равенством в hashCode
и equals
, если используется наследование. Но с другой стороны, это все еще очень элегантный способ решения некоторых проблем.
Кроме того, даже если наследование можно заменить делегированием, можно утверждать, что они по-прежнему достигают разных целей и дополняют друг друга - они не передают одно и то же намерение , которое не улавливается чистым технический эквивалентность.
(Моя теория состоит в том, что когда кто-то начинает делать ОО, у нас возникает соблазн чрезмерно использовать наследование, потому что оно воспринимается как особенность языка. Затем мы изучаем делегирование, которое является шаблоном / подходом, и мы учимся Мне это тоже нравится. Через некоторое время мы находим баланс между обоими и развиваем чувство интуиции, в каком из них лучше. В этом случае, как вы можете видеть, мне все еще нравятся оба, и оба заслуживают некоторой осторожности, прежде чем быть введен.)
Некоторая литература
Наследование и делегирование
альтернативные методы для приращения
определение и обмен. Она имеет
Считается, что делегация
обеспечивает более мощную модель. это
бумага демонстрирует, что есть
«Естественная» модель наследования, которая
захватывает все свойства
делегация. Независимо, наверняка
ограничения на способность
Делегация для захвата наследства
продемонстрировал. Наконец, новая структура
который полностью захватывает обе делегации
и наследование намечено, а некоторые
Последствия этого гибрида
Модель исследована.
Один из самых интригующих - и на
в то же время наиболее проблематично - понятия в
объектно-ориентированное программирование
наследование. Наследование обычно
рассматривается как особенность, которая
различает объектно-ориентированный
программирование от других современных
парадигмы программирования, но исследователи
редко соглашаются на его значение и использование. [...]
Из-за сильной связи классов и распространения ненужных учеников
по наследству предложение использовать композицию и делегирование стало обычным делом.
Представление соответствующего рефакторинга в литературе может привести к тому, что
такое преобразование является простым делом. [...]