23种设计模式(7):装饰者模式

理解装饰者模式在软件设计中的应用
本文详细解释了装饰者模式的概念及其在解决软件设计问题中的优势,通过星巴克咖啡菜单的例子,展示了如何利用装饰者模式动态地扩展对象功能,避免了类的爆炸性增长,并强调了组合复用原则的重要性。

转载于:http://blog.youkuaiyun.com/zhonghuan1992/article/details/38432915

装饰者(Decorator)模式又叫包装模式,用组合的方式来拓展对象的功能,是继承关系的一个替代方案。

定义说明:装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰着提供了比继承更富有弹性的替代方案。

 

从实例中体会

         实例来自 HeadFirst一书(建议读该书,例子太赞了),是星巴克的例子。星巴克的咖啡很有名(穷学生,现在喝不起o(╯□╰)o)。他们供应很多种类的咖啡。一开始他们的类设计是下面这样的。

        

         但是因为购买咖啡的时候,会加入更重调料,比如:蒸奶(Steamed Milk),豆浆(Soy),摩卡(Mocha,也就是巧克力风味的),或者覆盖奶泡。星巴克会针对不同的调料收取不一样的费用。所以订单系统必须考虑这些。想想,一开始我们遇到这种问题会怎么做,让每个特别的咖啡豆+调料都自成一个类,似乎可以解决问题,但是,如果调料很多,咖啡豆种类不少的话,总的类的数量=咖啡豆种类*调料数量。其实挺多类的。这样是不行的。    

         那怎么办,在Beverage本身下手?设计成下面这样的结构?

        

         学了开闭原则(忘了可以看这里),我们明白,这种做法违法了开闭原则,还有一点,还记得组合复用原则么?优先使用组合而不是继承,这里,应该优先考虑组合。

         在这里使用装饰者模式来解决。它是这样的,最先开始,我们选择咖啡豆种类,这里选择种类1

         然后添加了摩卡(Mocha)调料,使用摩卡(Mocha)来装饰咖啡豆1

         接着,再加点牛奶(milk),


         当计算价格的时候,我们从咖啡豆开始算起到最外面,或者从最外面开始算起到最里面,都能够算出价格来。

 

装饰者模式类图:

        

 

从上面的类图中,有四个角色:

1 抽象构件(Component):给出一个抽象接口,以规范准备接收附加责任的对象

2 具体构件(ConcreteComponent):定义一个将要接受附加东西的类

3 装饰角色(Decorator):一般的装饰者,具体给具体构件装饰的任务延迟到具体装饰者

4 具体装饰者(ConcreteDecorator):通过持有具体构件,附加给具体构件一些方法和属性。

 

针对上面的例子,我们的解决方案的类图为:

        

解决方案的代码吐下:

[java]  view plain copy
  1. interface Beverage{  
  2.     String description = "unknown beverage";  
  3.     public String getDescription();//返回描述的  
  4.     public double cost();//返回价格的  
  5. }  
  6.   
  7. class CoffeeBean1 implements Beverage{  
  8.     String description = "选了咖啡豆1:";  
  9.     public String getDescription(){  
  10.         return description;  
  11.     }  
  12.     public double cost(){  
  13.         return 30;//基本价格30元  
  14.     }  
  15. }  
  16.   
  17. class CoffeeBean2 implements Beverage{  
  18.     String description = "选了咖啡豆2:";  
  19.     public String getDescription(){  
  20.         return description;  
  21.     }  
  22.     public double cost(){  
  23.         return 28;//基本价格28元  
  24.     }  
  25. }  
  26.   
  27. class Decorator implements Beverage{  
  28.     String description = "unknown 装饰";  
  29.     Beverage beverage;  
  30.     public String getDescription(){  
  31.         return description;  
  32.     }  
  33.     public double cost(){  
  34.         return 0;//由子类来决定具体的装饰价格  
  35.     }  
  36. }  
  37.   
  38. class Milk extends Decorator{  
  39.     String description = "加了牛奶";  
  40.     public Milk(Beverage beverage){  
  41.         this.beverage=beverage;  
  42.     }  
  43.     public String getDescription(){  
  44.         return beverage.getDescription()+"\n"+description;//还有被装饰者的描述  
  45.     }  
  46.     public double cost(){  
  47.         return 5+beverage.cost();//加牛奶的价格是5元,还得加上里面beverage的价格  
  48.     }  
  49. }  
  50. class Soy extends Decorator{  
  51.     String description = "加了豆浆";  
  52.     public Soy(Beverage beverage){  
  53.         this.beverage=beverage;  
  54.     }  
  55.     public String getDescription(){  
  56.         return beverage.getDescription()+"\n"+description;//还有被装饰者的描述  
  57.     }  
  58.     public double cost(){  
  59.         return 4+beverage.cost();//加豆浆的价格是4元,还得加上里面beverage的价格  
  60.     }  
  61. }  
  62. class Mocha extends Decorator{  
  63.     String description = "加了摩卡";  
  64.     public Mocha(Beverage beverage){  
  65.         this.beverage=beverage;  
  66.     }  
  67.     public String getDescription(){  
  68.         return  beverage.getDescription()+"\n"+description;//还有被装饰者的描述  
  69.     }  
  70.     public double cost(){  
  71.         return 6+beverage.cost();//加摩卡的价格是6元,还得加上里面beverage的价格  
  72.     }  
  73. }  


 

测试代码:

[java]  view plain copy
  1. public class Main{  
  2.     public static void main(String[] args){  
  3.         Beverage coffee=new CoffeeBean1();//一开始选了咖啡豆1  
  4.         coffee=new Mocha(coffee);//加了摩卡  
  5.         coffee=new Milk(coffee);//加了牛奶  
  6.         System.out.println(coffee.getDescription());  
  7.         System.out.println("咖啡的价格为:"+coffee.cost());  
  8.     }  
  9. }  




结果:

何时使用装饰者模式:

         1需要扩展一个类的功能,或给一个类增加附加责任。

         2需要动态的给一个对象增加功能,这些功能可以再动态地撤销。

         3需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得不现实。

 

装饰者模式优点:

         1装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性。装饰者模式允许系统动态的决定是否需要装饰。而继承关系早系统运行前就决定了。

         2通过使用不同的装饰者的排列组合,可以有很多的组合。

缺点装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值