Hello,即将要写的这篇文章,是对刚刚学习完的装饰者模式的一个总结啦,也不是什么技术难点,就是巩固一下啦。
一.装饰者模式的定义
装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
只看定义真的有些不明白,先简单说明一下,下面还有例子呢。
(1)定义中提到了继承,看来装饰者模式是来解决扩展功能时使用继承的不足的;
(2)可以做到运行时装饰类,给对象赋予新的职责。
(3)还是看下面的例子吧。
二.实例--饮品店
饮品店里有,饮品--咖啡、果汁、茶类,饮品中可以加不同的配料--摩卡、牛奶、糖、奶泡;不同的饮品加上不同的配料有不同的价钱,怎样实现呢?
方式一:单纯的继承
最突出的缺点--造成类爆炸(组合的种类太多);
方式二:使用装饰者模式
1.装饰者模式的组成:抽象组件(Beverage)、具体组件(Coffee、Tea等)、抽象装饰者(IngredientDecorator)、具体装饰者(Mocha、Milk等),以例子说明的关系图如下:
2.代码示例:
抽象组件--超类--Beverage:
public abstract class Beverage { //description实例变量表示不同的描述,由子类赋值使用 String description = "Uknown Beverage"; public String getDescription() { return description; } //抽象方法,由子类实现 public abstract double cost(); }
具体组件--B_Coffee、B_FruitJuice等:
public class B_Coffee extends Beverage{ /** * 在构造器中设置饮料的描述 */ public B_Coffee(){ description = Description.COFFEE; } /** * 实现父类--抽象组件中的抽象方法 * 计算该饮料的价钱 */ public double cost() { return Cost.COFFEE; } }
public class B_FruitJuice extends Beverage{ public B_FruitJuice(){ description = Description.FRUIT_JUICE; } public double cost() { return Cost.FRUIT_JUICE; } }
抽象装饰者--IngredientDecorator:
/** * 继承的目的是为了IngredientDecorator能够取代Beverage * @author wangzhaoli * */ public abstract class IngredientDecorator extends Beverage{ /** * IngredientDecorator中覆盖父类中的getDescription()方法 * 继承IngredientDecorator的所有观察者需各自实现 */ public abstract String getDescription(); }
具体装饰者们--C_Mocha、C_Milk等:
/** * C_Mocha是一个装饰者 * C_Mocha继承的CondimentDecorator * CondimentDecorator继承了Beverage * @author wangzhaoli * */ public class C_Mocha extends IngredientDecorator{ /** * 要让C_Mocha能够引用一个Beverage,做法是: * 1.用一个实例变量记录Beverage,也就是被装饰者; * 2.想办法让Beverage被记录到实例变量中,即构造器参数实例化。 */ private Beverage beverage; public C_Mocha(Beverage beverage){ this.beverage = beverage; } /** * 实现父类CondimentDecorator中的抽象方法 */ public String getDescription() { //利用委托的方法得到之前的描述 return beverage.getDescription() + "," + Description.MOCHA; } /** * 实现父类的父类Beverage中的抽象方法 */ public double cost() { return beverage.cost() + Cost.MOCHA; } }
public class C_Milk extends IngredientDecorator{ private Beverage beverage; public C_Milk(Beverage beverage){ this.beverage = beverage; } public String getDescription() { return beverage.getDescription() + "," + Description.MILK; } public double cost() { return beverage.cost() + Cost.MILK; } }
测试类--main:
public class MainTest { public static void main(String[] args) { Beverage fruitJuice = new B_FruitJuice(); System.out.println(fruitJuice.getDescription()+":"+fruitJuice.cost()); System.out.println(); Beverage coffee = new B_Coffee(); coffee = new C_Mocha(new C_Mocha(new C_Suger(coffee))); System.out.println(coffee.getDescription()+":"+coffee.cost()); System.out.println(); Beverage tea = new B_Tea(); tea = new C_Mocha(tea); tea = new C_Milk(tea); tea = new C_Suger(tea); tea = new C_Form(tea); System.out.println(tea.getDescription()+":"+tea.cost()); System.out.println(); } }
测试结果:
Fruit Juice:8.0 Coffee,Suger,Mocha,Mocha:9.5 Tea,Mocha,Milk,Suger,Form:9.5
二.由实例说明装饰者模式
1.装饰者模式中很好的体现了组合(composition)和委托(delegation):
(1)利用继承设计子类的行为是在编译时静态决定的,利用组合的做法扩展对象的行为可以在运 行时动态的进行扩展;
(2)利用继承达到"类型匹配",而不是获得"行为",新的行为是由"组合对象"得来的;
(3)利用组合和委托可以实现在运行时具有继承的效果;
2.装饰者模式完全遵循"开放--关闭原则":类应该对扩展开放,对修改关闭。
3.以例子说明装饰者的使用:
拿一个咖啡对象,用摩卡装饰它,再用牛奶装饰它,然后调用cost()方法,并依赖委托 (delegate)将各种配料的价格加上去。
4.每个具体的组件都可以单独使用,或者被装饰者包装起来动态的加上新行为使用;
5.装饰者与抽象组件是"有一个"的关系,所以需要在每一个具体装饰者中定义一个实例变量以保存
某个具体组件的引用;
6.装饰者的新行为是指:通过在旧行为前面/后面加上一些计算、拼接等处理;
7.装饰者和被装饰者对象有相同的超类型;
8.可以用一个或多个装饰者包装一个对象;
9.装饰者可以所委托被装饰者的行为之前/之后,加上自己的行为,以达到指定的目的;