本文为阅读《Head First 设计模式》一书的摘要总结
装饰者模式
定义
装饰者模式 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
类图:
装饰者和被装饰者都是组件,都有相同的超类型。
每个装饰者都有一个组件(对Component
对象的引用),该组件属于被包装对象。
包装者中可以添加新的行为,这些行为可以通过在旧行为之前或之后做一些计算来添加的。
装饰者模式中的继承和组合:
ConcreteComponent
和Decorator
都继承了Component
,这里使用继承不是为了获得行为,而是为了装饰者与被装饰者达到 类型匹配,因为装饰者必须能取代被装饰者。当我们将装饰者与组件组合时,就是在加入新的行为。所的到的新行为,并不是继承自超类,而是由组合对象(装饰者与被装饰者行为的组合)得来的。
示例
一个可以组合成不同种类饮料并计算器价格的Demo:
共同的超类:
public abstract class Beverage {
protected String description = "Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
装饰者:
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription(); //继承该类的子类必须重新实现该方法
}
public class Mocha extends CondimentDecorator{
private Beverage beverage; //关键之处
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
return beverage.cost() + .20;
}
}
被装饰者:
public class Espresso extends Beverage {
public Espresso(){
description = "Espresso";
}
public double cost(){
return 1.99;
}
}
装饰:
public class StartbuzzCoffee {
public static void main(String[] args){
Beverage beverage = new Espresso();//不被任何装饰者修饰
System.out.println(beverage.getDescription() + ": $"+ beverage.cost());
Beverage beverage1 = new Espresso();//被两个Mocha修饰
beverage1 = new Mocha(beverage1);
beverage1 = new Mocha(beverage1);
System.out.println(beverage1.getDescription() + ": $" + beverage1.cost());
}
}
在java.io
包下,许多类都是装饰者。
装饰者模式的一些弊端:
- 在设计中加入大量的小类。
- 存在类型问题。有些代码会依赖特定的类型,一旦这些代码被装饰者装饰,代码的类型就被装饰者代替了。
- 在使用装饰者模式实例化组件时,不仅要实例化组件,还需要实例化一大堆装饰者,这增加了代码的复杂度。