设计模式之装饰者模式
2017-12-31 13:00
316 查看
装饰者概述
动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
问题的抛出
开始的类设计如下:
但是有的顾客需要添加调料,比如说豆浆,摩卡等等。还需要根据这些调料收取不同的费用,所以订单系统开始尝试变化,第一个尝试如下:
看看这个设计有多么的糟糕,没中不同的饮料加调料的组合都需要生成一个新类,不敢想象会有多少个类存在,况且一旦某个调料价格变动,要改多少的类,维护很困难。
那么再来看看第二种尝试:是利用实例变量和继承,把这些调料全部放在超类中。
我们来仔细思考下这种设计的缺陷:
1)调料价格的改变会使我们更改现有的代码
2)一旦出现新的调料,就需要加上新的方法,并改变超类中的cost方法
3)比如有个新的饮料茶,某些调料并不合适(奶泡),但是子类都必须继承haswhip方法。这是很糟糕的事,就像不会叫的鸭子还必须有会飞的方法!
4)利用继承设计子类的行为,是在编译时候就静态决定了,而且所有的子类都会继承相同行为。
我们所需要的系统是能够巧妙的将多个新行为,或者设计超类的时候还没想到的职责加在对象上,而且不用修改代码,为此而努力
由这个想法我们提出新的设计原则:类应该对扩展开放,对修改关闭。这样的设计具有弹性可以应对改变,可以接受新的行为来应对改变的需求。但是我们需要注意在选择需要被扩展的代码部分要十分小心。每个地方都使用开放-关闭原则是一种浪费,也没必要,还会导致代码变得更加复杂且难以理解。
认识装饰者模式
比方说顾客想要摩卡咖啡。1)先拿一个深焙咖啡对象
2)以摩卡对象装饰它
3)调用cost方法,依赖委托将调料的价格加上去
从上图可以看出:
1)装饰者和被装饰者具有相同的超类型
2)可以用一个或者多个装饰者去包装一个对象
3)既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它
4)装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
5)对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
现在我们可以来看看代码了:
package designPattern; public abstract class Beverage { String description ="Unkonwn Beverage"; public String getDescription(){ return description; } //cost()必须在子类中实现 public abstract double cost(); } //必须让Condiment Decorator 能够取代Beverage 所以扩展自Beverage类 abstract class CondimentDecorator extends Beverage{ //所有调料装饰者必须重新实现getDescription方法 public abstract String getDescription(); } //饮料 浓缩咖啡 需要为具体饮料设置描述以及实现cost方法 class Espresso extends Beverage{ public Espresso(){ description="Espresso"; } @Override public double cost() { return 1.99; } } class HouseBlend extends Beverage{ public HouseBlend(){ description="HouseBlend"; } @Override public double cost() { return 0.99; } } //装饰者摩卡 class Mocha extends CondimentDecorator{ /*思路: 1)用一个实例变量记录饮料,也就是被装饰者 2)想办法让被装饰者被记录到实例变量中,用构造函数把饮料当做 构造函数参数传入到实例变量中 * */ Beverage beverage; public Mocha(Beverage beverage){ this.beverage=beverage; } //为了完整的描述饮料(包括使用的调料) @Override public double cost() { return 0.2+beverage.cost(); } @Override public String getDescription() { return beverage.getDescription()+",Mocha"; } } //装饰者 Soy class Soy extends CondimentDecorator { Beverage beverage; public Soy(Beverage beverage) { this.beverage = beverage; } @Override public double cost() { return 0.6 + beverage.cost(); } @Override public String getDescription() { return beverage.getDescription() + ",Soy"; } } //装饰者 Whip class Whip extends CondimentDecorator { Beverage beverage; public Whip(Beverage beverage) { this.beverage = beverage; } @Override public double cost() { return 0.7 + beverage.cost(); } @Override public String getDescription() { return beverage.getDescription() + ",Whip"; } } //下订单了 class StarbuzzCoffee{ public static void main(String[] args) { //制造一杯浓缩咖啡 用Mocha,奶泡,豆浆装饰的 Beverage beverage=new Espresso(); beverage=new Soy(beverage); beverage=new Mocha(beverage); beverage=new Whip(beverage); System.out.println(beverage.getDescription()+" $"+beverage.cost()); } }
要点
�继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。� 在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。
� 组合和委托可用于在运行时动态地加上新的行为。
� 除了继承,装饰者模式也可以让我们扩展行为。
� 装饰者模式意味着一群装饰者类 , 这 些 类 用 来 包 装 具 体 组
件。
� 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型都经过接口或继承实现)。
� 装饰者可以在被装饰者的行为前面与/或后面加上自己的行为 , 甚 至 将 被 装 饰 者 的 行 为整个取代掉,而达到特定的目的。
� 你可以用无数个装饰者包装一个组件。
� 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
� 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂
小练习
package designPatternExe.Decorator; /* * 1:米线有三种,干浆、酸浆和水米线。(以后也不好说) * 2. 配料有三种,豆腐、鸡蛋、牛肉,今后还会更多。 * 3. 客户可疑随心所欲的要各种米线搭配各种配料,配料可以加同一种加多份,或者不同种加多份。 * */ public class dec_1 { public static void main(String[] args) { /*不断的装饰,一个类包装一个类,有点像在类 中加入新的功能,把上个类的引用给当前类就好了, 所以这也是为什么装饰类和被装饰类要类型一致, 还能附加新的功能。 * */ //1:不需要配料的酸浆米线 MiXian sjmx=new SuanJiang(); System.out.println(sjmx.getDescription()+","+sjmx.cost()); //2:来一份撒酸浆牛肉米线 MiXian sjnrmx=new SuanJiang(); sjnrmx=new Beef(sjnrmx,1); System.out.println(sjnrmx.getDescription()+","+sjnrmx.cost()); //3:来一份酸浆牛肉鸡蛋米线 MiXian sjnrjdmx=new SuanJiang(); sjnrjdmx=new Beef(sjnrjdmx,1); sjnrjdmx=new Egg(sjnrjdmx,1); System.out.println(sjnrjdmx.getDescription()+","+sjnrjdmx.cost()); //4:来一份酸浆牛肉米线 ,牛肉来两份 MiXian sjnr2mx=new SuanJiang(); sjnr2mx=new Beef(sjnr2mx,2); System.out.println(sjnr2mx.getDescription()+","+sjnr2mx.cost()); } } //米线(被装饰者) abstract class MiXian{ String description="unkown mixian"; public String getDescription() { return description; } abstract double cost(); } class GanJiang extends MiXian{ public GanJiang() { this.description="Ganjiang"; } @Override double cost() { return 1.1; } } class SuanJiang extends MiXian{ public SuanJiang() { this.description="SuanJIang"; } @Override double cost() { return 2.2; } } class ShuiMiXian extends MiXian{ public ShuiMiXian() { this.description="ShuiMixian"; } @Override double cost() { return 3.3; } } //配料(装饰者)必须与被装饰者保持一样类型 //从而能取代被装饰者 abstract class PeiLiao extends MiXian{ public abstract String getDescription(); } class DouFu extends PeiLiao{ MiXian miXian; public int count=1; public DouFu() { this.description="DouFu"; } public DouFu(MiXian miXian,int count) { this.description="DouFu"; this.miXian = miXian; this.count=count; } @Override double cost() { return miXian.cost()+0.2*count; } @Override public String getDescription() { return miXian.getDescription()+","+this.description; } } class Egg extends PeiLiao{ MiXian miXian; public int count=1; public Egg(MiXian miXian,int count) { this.miXian = miXian; this.count=count; this.description="Egg"; } public Egg() { this.description="Egg"; } @Override double cost() { return miXian.cost()+0.3*count; } @Override pub a4bf lic String getDescription() { return miXian.getDescription()+","+this.description; } } class Beef extends PeiLiao{ public int count=1; MiXian miXian; public Beef() { this.description="Beef"; } public Beef(MiXian miXian,int count) { this.miXian = miXian; this.count=count; this.description="Beef"; } @Override double cost() { return miXian.cost()+0.5*count; } @Override public String getDescription() { return miXian.getDescription()+","+this.description; } }
相关文章推荐
- 一天一个设计模式---装饰者模式
- 设计模式 -- 装饰者模式
- 设计模式之装饰者模式
- 生拉硬套设计模式(一),关于装饰者模式在Android项目中的运用。
- 每天一个设计模式之装饰者模式
- 设计模式—装饰者模式
- 设计模式--装饰者模式
- 设计模式------装饰者模式
- JavaSE(16)(装饰者设计模式)
- Java设计模式之装饰者模式
- 设计模式-装饰者模式
- 【菜鸟学设计】——装饰者模式(Decorator)
- Java设计模式-装饰者设计模式
- PHP设计模式之装饰者模式
- 设计模式之-装饰者模式
- 设计模式之装饰者模式
- PHP设计模式之装饰者模式
- 设计模式:装饰者模式
- 设计模式 2 —— 装饰者模式
- 设计模式之装饰者模式(二)---java中的装饰者I/O结构