装饰者模式
动态地将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。
首先必须有抽象超类Component,并有抽象方法methodA();
实现继承此超类Component的具体类ConcreteComponent,这些具体类在模式里作为被装饰者存在;
另外定义一个装饰抽象类Decorator继承此超类Component;
继承自装饰抽象类的Decorator的子类被称为装饰者类;
每个装饰者类都有一个实例变量以保存某个Component的引用;
装饰者类将被装饰者引入到Component实例变量中(通常将被装饰者以构造器的参数形式引入),如此便可以在装饰者类自己的方法里调用被装饰者方法的作用(例如在methodA()方法内使用Component.methodA()),进而实现装饰者模式扩展功能,而不需要修改代码(类应该对扩展开放,对修改关闭)。
以添加多种调料后饮料价格的计算为例:
Beverage为超象超类,Condimentdecorator为装饰者抽象类,Espresso为Beverage的具体类(一种饮料),而Mocha和Milk为装饰者类。那么所有类都有cost方法。
Mocha和Milk都包含Beverage的行为变量,并在构造函数处引入该对象实例,而cost方法定义为:
public double cost(){
return 0.20 + beverage.cost();//动态地将责任附加到对象上
}
便可以实现计算出加了Mocha和Milk的Espresso饮料的价格:
Beverage beverage = new Espresso();
beverage = new Milk(beverage);
beverage = new Mocha(beverage);
System.out.println(beverage.cost());//打印出的就是添加了Mocha和Milk的Espresso的价格。
Java.io包里有很多类使用了装饰者模式,例如常见的:
InputStream in= new LineNumberInputStream(new BufferedImputStream(new FileInputStream("test.txt")));
InputStream为抽象超类,FileInputStream是可以被装饰者包起来的具体组件类。
LineNumberInputStream和BufferedImputStream则是具体装饰者类,而它们的父类FilterInputStream则是一个抽像装饰者类。
要点:
1,装饰者反映出被装饰者的组件类型(事实上,他们具有相同的类型,都经过接囗或继承实现)
2,装饰者模式意味着一群装饰者类,这些类用于包装具体组件
3,理论上可以用无数个装饰者包装一个组件
优点:
除了继承,装饰者模式也可以让我们扩展行为(装饰者模式为我们提供了一种继承之外的扩展行为的方法)。
装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
缺点:
装饰者会导致设计出现许多小对象,如果过度使用,会让程序变得复杂。
新的设计原则:
类应该对扩展开放,对修改关闭。