-
需求分析:
现在有一家咖啡店, 提供不同类型的咖啡, 但是顾客在购买咖啡的同时可以要求加入各种调料. 咖啡店会根据加入的调料收取不同的费用. 假设现在有 4 种调料./** * 抽象的饮料类 */ public abstract class Beverage { private Stirng description; private boolean hasMilk; private boolean hasSoy; private boolean hasMocha; private boolean hasWhip; protected abstract double getCost(); public void getDescription() { return description; } public boolean hasMilk() { return this.hasMilk; } public void setMilk(boolean hasMilk) { this.hasMilk = hasMilk; } public boolean hasSoy() { return this.hasSoy; } public void setSoy(boolean hasSoy) { this.hasSoy = hasSoy; } public boolean hasMocha() { return this.hasMocha; } public void setMocha(boolean hasMocha) { this.hasMocha = hasMocha; } public boolean hasWhip() { return this.hasWhip; } public void setWhip(boolean hasWhip) { this.hasWhip = hasWhip; } } /** * 具体类型的咖啡-深焙咖啡 */ public class DarkRoast extends Beverage { public DarkRoast() { this.description = "Dark Roast"; } public double getCost() { // 基本价钱 double cost = 1.0; if (hasMilk()) { cost += 0.1; } if (hasSoy()) { cost += 0.2; } if (hasMocha()) { cost += 0.3; } if (hasWhip()) { cost += 0.4; } return cost; } } /** * 客户端 */ public class Client { public static void main(String[] args) { DarkRoast darkRoast = new DarkRoast(); darkRoast.setMilk(true); darkRoast.setMocha(true); System.out.println(darkRoast.getCost()); } }现在的问题是咖啡的类型有很多, 加入现在某种调料的价钱发生了改变, 每种咖啡类的
cost()方法就需要进行调整; 如果出现新的调料, 每种咖啡类的cost()方法又需要增加判断; 对于某些调料来说, 某些咖啡类型并不能添加, 但是在类中仍然继承了这些调料以及相关的方法; 顾客还可能需要将某种调料增加好几倍, 例如需要加双倍摩卡的咖啡. 可以采用装饰者模式来解决这个问题.首先创建一个深焙咖啡对象, 然后以摩卡装饰它, 然后再用摩卡装饰它, 这样就可以得到加双倍摩卡的咖啡了. 如果需要其它的调料, 可以用其它的调料继续装饰它, 最终就可以得到想要的咖啡了.
/** * 抽象的饮料类 */ public abstract class Beverage { protected String description; public String getDescription() { return this.description; } public abstract double cost(); } /** * 抽象的装饰者类 */ public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); } /** * 具体的咖啡类-浓缩咖啡, 这时候的咖啡没有增加任何调料 */ public class Espresso extends Beverage { public Espresso() { this.description = "Espresso"; } public double getCost() { // 基本价钱 return 1.0; } } /** * 摩卡调料 */ public class Mocha extends CondimentDecorator { private Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } public String getDescription() { return beverage.getDescription() + ", Mocha"; } public double getCost() { return beverage.getCost() + 0.2; } } /** * 客户端 */ public class Client { public static void main(String[] args) { Beverage expresso = new Espresso(); Beverage expressoWithMocha = new Mocha(expresso); Beverage expressoWithDoubleMocha = new Mocha(expresso); } }原料价格改变不会影响到具体的咖啡类型; 出现新的调料只需要增加新的装饰者实现类即可; 调料也是按客户需求增加的, 不会增加多的调料.
-
装饰者模式定义:
Attach additional responsibilities to an object dynamiclly keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality(动态地给一个都西昂添加一些额外的职责. 就增加功能来说, 装饰者模式相比生成子类更为灵活).装饰者模式一般用来扩展类的功能, 或者为类增加新的功能. 通过装饰者模式给类增加功能和通过继承给类增加功能的区别在于: 装饰者模式给类增加功能具有动态性.

-
装饰者模式的应用:
Java 的 I/O 接口是装饰者模式的典型应用.
InputStream对应装饰者模式的Component,FileInputStream,StringBufferInputStream,ByteArrayInputStream对应装饰者模式的ConcreteComponent;FilterInputStream对应装饰者模式的Decorator,PushBackInputStream,BufferedInputStream,DataInpustStream,LineNumberInputStream对应装饰者模式的ConcreteDecorator.
-
参考:
[1] : Java 库中的设计模式
[2] : 设计模式之禅
[3] : Head First 设计模式