再次强调设计的重要原则:对扩展开放,对修改关闭。在设计中要尽量避免对之前源代码的修改。
为适应扩展的特性,除了继承之外,还可以用装饰者模式:动态的将新的功能附加到对象上。换句话说,装饰者模式就是有一群装饰者类,这些类包裹起具体的组件。在java中,最典型的装饰者模式就是java I/O
FileInputStream是被包装的组件,有最基本的读取字节的功能。BufferInputStream是一个具体的装饰者,它加入了两种新的行为:readLine()和缓冲输入;LineNumberInputstream也是一个具体的装饰者它在BufferInputStream之上又加入了计算行数的功能。
具体例子:咖啡馆订单系统。咖啡馆有多款咖啡,例如HouseBllend、DarkRoast;顾客在购买咖啡时经常要求在咖啡中加上各种调料例如Streamed Milk,Mocha。根据客户不同的要求收取不同的费用。
UML图:调料类CondimentDecortor是饮料类Beverage的装饰类。在装饰类的两种调料中,有一个实例变量Beverage,用它来记录需要包裹的实例。注意:最终的结果是经过装饰类包装之后的类,也就是说装饰类可以取代Beverage,所以装饰类CondimentDecortor必须继承自Beverage
饮料 Beverage
1 package com.coffee; 2 3 public abstract class Beverage { 4 protected String description="Unknown Beverage"; 5 protected int Size;//1:小杯 2:中杯 3:大杯 6 7 public String getDescription() { 8 return description; 9 } 10 11 public int getSize() { 12 return Size; 13 } 14 15 public abstract double cost();//cost在子类中实现 16 17 18 }
HouseBlend咖啡具体实现饮料类
1 package com.coffee; 2 3 public class HouseBlend extends Beverage{ 4 public HouseBlend(int size) { 5 description="HouseBlend"; 6 Size=size; 7 if(getSize()==1){ 8 description+="Small"; 9 }else if(getSize()==2){ 10 description+="Middle"; 11 }else if(getSize()==3){ 12 description+="Large"; 13 } 14 } 15 16 public double cost() { 17 double Cost=1.99; 18 if(getSize()==1){ 19 Cost+=1.0; 20 }else if(getSize()==2){ 21 Cost+=2.0; 22 }else if(getSize()==3){ 23 Cost+=3.0; 24 } 25 return Cost; 26 } 27 28 }
调料装饰类CondimentDecorator
1 package com.condiment; 2 3 import com.coffee.Beverage; 4 5 public abstract class CondimentDecorator extends Beverage { 6 public abstract String getDescription(); 7 public abstract int getSize(); 8 9 }
Mocha调料实现CondimentDecorator
1 package com.condiment; 2 3 import com.coffee.Beverage; 4 5 public class Mocha extends CondimentDecorator{ 6 Beverage beverage; 7 8 public Mocha(Beverage beverage) { 9 this.beverage = beverage; 10 } 11 12 public int getSize(){ 13 return Size; 14 } 15 16 public String getDescription() { 17 // TODO Auto-generated method stub 18 String order="Order:"; 19 if(getSize()==1){ 20 order+="Small"; 21 }else if(getSize()==2){ 22 order+="Middle"; 23 }else if(getSize()==3){ 24 order+="Large"; 25 } 26 return order+beverage.getDescription()+",Mocha"; 27 } 28 29 30 public double cost() { 31 // TODO Auto-generated method stub 32 double cost=beverage.cost()+.20;//取得之前饮料的加个加上摩卡的加个.20 33 if(getSize()==1){ 34 cost+=1.0; 35 }else if(getSize()==2){ 36 cost+=2.0; 37 }else if(getSize()==3){ 38 cost+=3.0; 39 } 40 return cost; 41 } 42 43 }