设计模式之装饰者模式
首先让我们看一下装饰者模式(我爱叫他套娃模式)的概念:动态的将责任附加到对象上,
若要扩展功能,装饰者提供了比继承者更有弹性的集成方案。
什么?没看懂?没关系,最后再来看这个概念,想让让我们来看一个咖啡屋项目(就是点各式
各样的咖啡)。
原本的设计如下:
看似很好的设计,但是别忘了,买咖啡时候我们会让他们给我们加一系列的调料,例如蒸奶、
摩卡......。所以,在这时咖啡店的设计就变成了,如下:
不错,你看到了类爆炸!
好啦,现在有对这个系统做出了改进,如下:
好啦,现在这个设计相比之前的的确好了许多,但是如果我们要修改配料呢?那么就必须修改
超类,这时候就违反了一条设计原则:类应该对扩展开放,对修改关闭!
所以这个时候,装饰者模式单诞生了!!!!!
来看个例子:
如果顾客现在要一杯摩卡和奶泡深培咖啡。那么,要做的是:
①拿一个深培咖啡(darkroast)对象
②以摩卡(mocha)对象装饰它
③以奶泡(whip)装饰它
④调用cost()方法,并依赖委托(delegate)将调料的几千加上去
如何工作?
①以darkroast对象开始
②顾客想要摩卡(mocha),所以建立一个mocha对象,并用它将darkroast对象包起来
③顾客也想要奶泡(whip),所以建立一个whip装饰者,并用它将mocha对象包起来。别
忘了,darkroast继承自beverage,且有一个cost()方法,用来计算饮料价钱
④现在,该是为顾客算钱的时候了。通过调用最外圈的装饰者的cost就可以办到,如下图:
好了,请记住装饰者和被装饰对象有相同的超类型!现在让我们写一些代码,了解他的工作吧:
首先看一下我们现在的设计图:
先从beverage类下手,这不需要改变原始设计。如下图:
1 public abstract class beverage { 2 string description = "unknown beverage"; 3 4 public string getdescription(){ 5 return description; 6 } 7 8 public abstract double cost(); 9 }
beverage很简单。让我们来实现condiment(调料)抽象类,也就是装饰这类吧:
1 public abstract class condimentdecorator extends beverage{ 2 beverage beverage; 3 4 public abstract string getdescription(); 5 }
现在,该是实现一些饮料的时候了!先从浓缩咖啡(espresso)开始:
espresso.java:
1 public class espresso extends beverage { 2 public espresso() { 3 description = "espresso"; 4 } 5 6 public double cost() { 7 return 1.99; 8 } 9 }
darkroast.java:
1 public class darkroast extends beverage { 2 public darkroast() { 3 description = "dark roast coffee"; 4 } 5 6 public double cost() { 7 return .99; 8 } 9 }
houseblend.java:
1 public class houseblend extends beverage { 2 public houseblend() { 3 description = "house blend coffee"; 4 } 5 6 public double cost() { 7 return .89; 8 } 9 }
开始协调料代码:
mocha.java:
1 public class mocha extends condimentdecorator { 2 public mocha(beverage beverage) { 3 this.beverage = beverage; 4 } 5 6 public string getdescription() { 7 return beverage.getdescription() + ", mocha"; 8 } 9 10 public double cost() { 11 return .20 + beverage.cost(); 12 } 13 }
milk.java:
1 public class milk extends condimentdecorator { 2 public milk(beverage beverage) { 3 this.beverage = beverage; 4 } 5 6 public string getdescription() { 7 return beverage.getdescription() + ", milk"; 8 } 9 10 public double cost() { 11 return .10 + beverage.cost(); 12 } 13 }
soy.java:
1 public class soy extends condimentdecorator { 2 public soy(beverage beverage) { 3 this.beverage = beverage; 4 } 5 6 public string getdescription() { 7 return beverage.getdescription() + ", soy"; 8 } 9 10 public double cost() { 11 return .15 + beverage.cost(); 12 } 13 }
whip.java:
1 public class whip extends condimentdecorator { 2 public whip(beverage beverage) { 3 this.beverage = beverage; 4 } 5 6 public string getdescription() { 7 return beverage.getdescription() + ", whip"; 8 } 9 10 public double cost() { 11 return .10 + beverage.cost(); 12 } 13 }
测试代码:
main.java:
1 public class main { 2 3 public static void main(string[] args) { 4 beverage beverage = new espresso(); 5 system.out.println(beverage.getdescription() 6 + " $" + beverage.cost()); 7 8 beverage beverage2 = new darkroast(); 9 beverage2 = new mocha(beverage2); 10 beverage2 = new mocha(beverage2); 11 beverage2 = new whip(beverage2); 12 system.out.println(beverage2.getdescription() 13 + " $" + beverage2.cost()); 14 15 beverage beverage3 = new houseblend(); 16 beverage3 = new soy(beverage3); 17 beverage3 = new mocha(beverage3); 18 beverage3 = new whip(beverage3); 19 system.out.println(beverage3.getdescription() 20 + " $" + beverage3.cost()); 21 } 22 }
结果:
上一篇: 桌面激光打印机日常故障判断方法谈
下一篇: 为Nginx添加SPDY功能