《Head First 设计模式》学习笔记——装饰者模式
概念
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
eg:
当我们需要设计一个饮料的订单系统,一般我们会先设计一个基类Beverage(饮料)
而当我们设计咖啡、果汁、奶茶这样具体的类时会采用继承的方式,并重写方法。
但是客户在购买咖啡时可能会有各种各样的需求,比如:加奶,加豆浆,加摩卡等,而这些调料需要收取不同的费用这个时候如果我们还使用继承的方法,就会出现HouseBlendWithSteamedMilkandMocha,DecafWithSteamedMilkandMocha等众多的类,显然这是不可取的
用装饰者模式解决
可以理解成汉语中的修饰词,装饰者模式也是通过对原始对象增加修饰,比如加奶的咖啡,加奶、加豆浆的咖啡,这样的形式不断的包裹独立的对象来满足客户的需求,如下所示:
eg:
顾客想要一杯深培咖啡,我们就造一个DarkRoast对象
现在顾客想要加摩卡,就建立一个Mocha对象,并用它将DarkRoast对象包起来
然后顾客又想加奶泡,就再建一个Whip装饰者
注意:
- 这些类都继承自Beverage超类
- 创建的Mocha、Whip可以和任意的饮料组成新的类型(如加了摩卡的奶茶,加了奶泡的果汁)
- 想要计算最后的价格只要调用最外圈装饰者(Whip)的cost()方法就可以
装饰者模式的特点
- 装饰者和被装饰者对象有相同的超类型
- 可以用一个或多个装饰者包装一个对象
- 既然装饰者和被装饰对象有相同的超类型,所以在任何时候需要原始对象(被包装的)的场合,可以用装饰过的对象代替它
- 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的
- 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
- 装饰者会导致设计中出现许多小对象,如果使用过度,会让程序变得很复杂
代码实现
饮料(Beverage)类
public abstract class Beverage{
String description = "Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
调料(Condiment)类
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
摩卡(Mocha)类
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription() + ",Mocha";
}
public double cost(){
return .20 + beverage.cost();
}
}
测试:
public class Coffee{
public static void main(String args[]){
Beverage beverage = new DarkRoast();@
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription()+" $"+beverage.cost());
}
}