我在这个页面上看到了下面的评论。我不明白为什么“装饰器关系可以在运行时改变”以及为什么“继承关系在编译时是固定的”。
装饰器被证明比继承更灵活,因为装饰器和它们装饰的对象之间的关系可以在运行时改变,但是基类和它们的扩展之间的关系在编译时是固定的
我在这个页面上看到了下面的评论。我不明白为什么“装饰器关系可以在运行时改变”以及为什么“继承关系在编译时是固定的”。
装饰器被证明比继承更灵活,因为装饰器和它们装饰的对象之间的关系可以在运行时改变,但是基类和它们的扩展之间的关系在编译时是固定的
如果你有三个类,A、B 和 C,那么无论你如何继承,你都有一个静态关系,例如 A:B 和 B:C。
另一方面,如果这三个都是装饰器,那么您可以在同一进程中以任意顺序装饰它们,例如 A(B(C)) 或 C(A(B))。
您可以随时装饰对象。假设你有一个,你可以在运行时FileInputStream
用它来装饰它。BufferedInputStream
如果这是由类继承设计的,您将无法将您的类型转换/转换FileInputStream
为任何其他类型。
使用装饰器,您只需编写一个将对象作为输入并返回某种包装器的方法。装饰器可以任意智能,可以针对不同的输入进行专门的实现,等等。
使用继承,您必须在编译时显式声明子类及其所有细节,然后实现固定。
我认为这些例子没有说明的是装饰器有一个对装饰类的引用,即它使用一个接口,假设你想在有人访问“列表”的最后一个元素时打印出“结束”,你可以子类化所有实现 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);
}
}