这次我们来学习一下装饰者模式,感谢head first design。
首先设想你在替一家咖啡馆做设计,开始时你的设计可能是这样的
但是这会导致什么问题呢?我们来看下图
这简直就是类的大爆炸!
面向对象的设计原则之中有非常重要的一条,那就是设计应该具有比较好的扩展性,而对修改源代码尽可能减少。正如观察者模式,runtime 时可以添加不同的观察者到subject上,不用修改subject。在此,我们介绍装饰者模式。
相当于图中的component,抽象类
package headfirst;
public abstract class Beverage {
protected String description="UnKnown Beverage";
public String getDescription(){
return this.description;
}
public abstract double cost();
}
装饰者
package headfirst;
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
具体的被装饰者
package headfirst;
public class Espresso extends Beverage{
public Espresso(){
description ="Espresso";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 1.99;
//返回espresso的价格
}
}
具体的被装饰者
package headfirst;
public class HouseBlend extends Beverage{
public HouseBlend(){
description="HouseBlend";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.89;
}
}
package headfirst;
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage=beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.2+beverage.cost();
}
}
测试代码如下:
package headfirst;
public class StarbuzzCoffee {
public static void main(String args[]){
Beverage beverage=new Espresso();
beverage=new Mocha(beverage);
beverage=new Mocha(beverage);
//双倍抹茶
System.out.println("my first beverage is "+beverage.getDescription());
System.out.println("it is "+beverage.cost()+"$");
Beverage beverage2=new HouseBlend();
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
System.out.println("my second beverage is "+beverage2.getDescription());
System.out.println("it is "+beverage2.cost()+"$");
}
}
输出如下:
my first beverage is Espresso,Mocha,Mocha
it is 2.39$
my second beverage is HouseBlend,Mocha,Mocha,Mocha
it is 1.49$
关键点是装饰者有被装饰者的接口,并且持有一个被装饰者的引用,然后再由具体被装饰者和具体装饰者来实现。