当前位置: 代码迷 >> 综合 >> HeadFirst(三)Decorator 装饰设计模式
  详细解决方案

HeadFirst(三)Decorator 装饰设计模式

热度:13   发布时间:2024-01-10 04:44:07.0

 

设计原则

类应该对扩展开发,对修改关闭

不修改现有代码的情况下,可以添加新的行为,这样的设计具有弹性,可以应对变化,提供新的功能。

 

装饰者模式完全遵循开放-关闭的原则

遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度

应该把注意力集中在主要的容易发生变化的地方,然后应用开放-关闭原则

 

 

装饰:最低层的功能不变,对外提供了更灵活更方便的方法

委托:低层功能调用还得依赖与具有该行为的对象,委托这个对象去完成它自己才能完成的事

 

 

 

咖啡馆的故事


 

Beverage为所有类的基类,它将作为方法的参数接受各种类型的子类对象

 

HouseBend,DarkRoster,Espresso,Decaf,都是被装饰对象,通过cost方法计算各自的价钱

 

CondimentDecorator继承Beverage,自身为一个抽象类,为子类封装共有的属性和方法

 

Milk,Mocha,Soy,Whip,都是装饰者,将对被装饰对象进行装饰,在内部会让被装饰者去调用自己的方法计算价格

 

 

公共的基类,将来作为方法的参数,接收各种子类对象

package decorator.coffee;import java.text.NumberFormat;public abstract class Beverage {public static enum BeverageSize {BIG, MEDIUM, SMALL;// 大杯,中杯,小杯}//杯子大小private BeverageSize size;public BeverageSize getSize() {return size;}public void setSize(BeverageSize size) {this.size = size;}//饮料描述信息protected String description = "Unknow Beverage";public String getDescription() {return description;}//需由子类去实现去方法public abstract double cost();/*** 计算总价时,加上杯子的钱(只能加1次)* @return*/public double costTotal() {double total = cost();if(size!=null) {switch (this.size.ordinal()) {case 0:total += 0.20;//大杯break;case 1:total += 0.15;//中杯break;case 2:total += 0.10;//小杯break;}}NumberFormat nf = NumberFormat.getInstance();nf.setMaximumFractionDigits(2);return Double.valueOf(nf.format(total));}
}

 

将要被装饰的类(一)

package decorator.coffee;public class Espresso extends Beverage {public Espresso() {this.description = "Espresso";}@Overridepublic double cost() {return 1.99;}}

 

 将要被装饰的类(二)

package decorator.coffee;public class HouseBlend extends Beverage {public HouseBlend() {this.description = "HouseBlend";}@Overridepublic double cost() {return 0.89;}}

 

 

中转作用的类,实现装饰者与被装饰者都是Beverage的子类

package decorator.condiment;import decorator.coffee.Beverage;/*** 继承Beverage,让装饰者继承它,这样装饰者(调料)与被装饰者(具体的饮料)都属于Beverage* 都是Beverage的子类,从而在面向父类/接口编程时,都可以作为参数传入到方法中!*/
public abstract class CondimentDecorator extends Beverage {//持有祖先的引用//通过祖先获取旁系,祖先对子孙的设计,这样便可以利用多态的功能,动态绑定子类对象了!//【这里的做法与javascript中getParentNode()获取sibing的思想有一丁点儿的类似】Beverage beverage;//实为组合的应用,特殊的地方:被组合的对象为自己的父类public CondimentDecorator(Beverage beverage) {this.beverage = beverage;//参数为父类,为多态做准备}@Overridepublic String getDescription() {return this.beverage.getDescription()+", "+this.getClass().getSimpleName();}}

 

装饰者(一)

package decorator.condiment;import decorator.coffee.Beverage;/*** 真正的装饰者**/
public class Mocha extends CondimentDecorator {public  Mocha(Beverage beverage) {super(beverage);//将实际的coffee传进来}@Overridepublic double cost() {return 0.20 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱}}

 

装饰者(二)

package decorator.condiment;import decorator.coffee.Beverage;/*** 真正的装饰者**/
public class Soy extends CondimentDecorator {public  Soy(Beverage beverage) {super(beverage);//将实际的coffee传进来}@Overridepublic double cost() {return 0.40 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱}}

 

装饰者(三)

package decorator.condiment;import decorator.coffee.Beverage;/*** 真正的装饰者**/
public class Whip extends CondimentDecorator {public  Whip(Beverage beverage) {super(beverage);//将实际的coffee传进来}@Overridepublic double cost() {return 0.30 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱}}

 

 

 

测试

package test;import decorator.coffee.Beverage;
import decorator.coffee.Beverage.BeverageSize;
import decorator.coffee.Espresso;
import decorator.condiment.Mocha;public class BeverageTest {public static void main(String[] args) {Beverage beverage = new Espresso();System.out.println(beverage.getDescription()+" $"+beverage.costTotal());beverage = new Mocha(beverage);System.out.println(beverage.getDescription()+" $"+beverage.costTotal());beverage = new Mocha(beverage);System.out.println(beverage.getDescription()+" $"+beverage.costTotal());//设置杯子的大小beverage.setSize(BeverageSize.BIG);System.out.println(beverage.getDescription()+" $"+beverage.costTotal());}
}

 

 

 

JAVA I/O中对装饰者模式的应用