我在this page看到了以下评论。我不明白为什么“装饰器关系可以在运行时改变”以及为什么“继承关系在编译时被修复”。
装饰器证明比继承更灵活,因为装饰器和它们装饰的对象之间的关系可以在运行时改变,但基类和它们的扩展之间的关系在编译时是固定的
答案 0 :(得分:5)
如果你有三个类,A,B和C,那么无论你如何继承,你都有一个静态关系,例如A:B和B:C。
另一方面,如果所有三个都是装饰器,那么你可以在同一个过程中以任何顺序装饰它们,例如A(B(C))或C(A(B))。
答案 1 :(得分:2)
您可以随时装饰对象。假设您有一个FileInputStream
,您可以在运行时使用BufferedInputStream
来装饰它。如果这是由类继承设计的,那么您将无法将FileInputStream
转换/转换为任何其他类型。
答案 2 :(得分:1)
使用装饰器,您只需编写一个将对象作为输入并返回某种包装器的方法。装饰器可以是任意智能的,可以为不同的输入提供专门的实现,等等。
使用继承,您必须在编译时显式声明子类及其所有细节,并在此之后修复实现。
答案 3 :(得分:1)
我认为这些例子没有说清楚,装饰者有一个对装饰类的引用,即它使用一个接口,想象你有人在访问'List'的最后一个元素时打印出'The End' ,你可以继承所有实现List的类,并拥有'MyArrayList,MyLinkedList,MyCopyOnWriteArrayList等,并覆盖get()方法,(繁琐,我相信你会同意),或者你可以使用装饰器并传递实现(即实际列表)在运行时,它由其接口引用,因此您只有一个新的get方法的实现。 考虑一下这个人为的例子(下面),关键是我可以将List的任何实现传递给ListDecorator并且它会工作,想象这样做是为了继承,我相信你会明白为什么装饰器有时会更好。
package decorator;
import java.util.ArrayList;
import java.util.List;
public class ListDecorator {
List realList;
public static void main(String[] args) {
// Here we are decorating an ArrayList but it could be anything
// that implements the List interface.
ListDecorator ld = new ListDecorator( new ArrayList() );
for(int i=0; i<10; i++)
ld.add( i );
for(int j=0; j<10; j++)
System.out.println("[j]="+ld.get(j) );
}
ListDecorator(List realList){
this.realList = realList;
}
public void add(Object o){
realList.add( o );
}
public Object get(int i){
if(i == realList.size() -1)
System.out.println("The end");
return realList.get(i);
}
}