为了账号安全,请及时绑定邮箱和手机立即绑定

装饰者模式 Decorator

标签:
Java

项目:咖啡计费系统

背景:现有系统中有一个抽象类Beverage,有2个抽象方法GetDescription和Cost。

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 饮料抽象类 5     /// </summary> 6     public abstract  class Beverage 7     { 8         protected string description = "饮料"; 9         protected float price = 0f;10         public abstract string GetDescription();11         12         public abstract float Cost();13     }14 }

 

需求:目前有综合咖啡、深焙咖啡、浓缩咖啡,调料有牛奶、摩卡、豆浆、奶泡。未来可能增加新的咖啡种类和调料,当顾客点咖啡时,要求能够获得咖啡的描述和价格。

设计方案1:设计综合咖啡、深焙咖啡、浓缩咖啡4个子类,继承Beverage。再用这4个子类分别派生4个子类,带有牛奶的综合咖啡,带有摩卡的综合咖啡,带有豆浆的综合咖啡...

分析:缺点时显而易见的,这样做导致“类爆炸”,一共需要3*4=12个子类。

设计方案2:把调料作为咖啡的属性设置在Beverage里,并增加方法HasMilk(),SetMilk()等类似的方法。

分析:缺点这样做无疑时从一个灾难跳进另一个灾难中。我们在开发中应当尽量避免修改已有代码,遵循“开闭原则”。而且当增加新的饮料时,又要修改基类。

另一个灾难是,子类在计算价格时,需要大量的分支结构来判断是否包含某种调料,以计算咖啡的价格,我们总是尽量的避免复杂的分支结构,这使得维护变得非常困难。

还有针对实现编程带来的问题,不能够动态的添加职责。

装饰者模式 Decorator 闪亮登场:

装饰者模式动态的将职责附加到对象上。若要扩展共呢个,装饰者提供了比继承更有弹性的替代方案。

1. 4个基类继承Beverage

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 综合咖啡 5     /// </summary> 6     public class HouseBlend:Beverage 7     { 8         public HouseBlend(float price) 9         {10             this.price = price;11             this.description = "综合咖啡";12         }13 14         public override float Cost()15         {16             return price;17         }18         public override string GetDescription()19         {20             return this.description;21         }22     }23 }

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 深焙咖啡 5     /// </summary> 6     public class DarkRoast:Beverage 7     { 8         public DarkRoast(float price) 9         {10             this.price = price;11             this.description = "深焙咖啡";12         }13         public override string GetDescription()14         {15             return this.description;16         }17         public override float Cost()18         {19             return price;20         }21     }22 }

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 浓缩咖啡 5     /// </summary> 6     public class Espresso:Beverage 7     { 8         public Espresso(float price) 9         {10             this.price = price;11             this.description = "浓缩咖啡";12         }13         public override float Cost()14         {15             return this.price;16         }17         public override string GetDescription()18         {19             return this.description;20         }21     }22 }

装饰者继承Beverage,注意这里继承的目的并不是为了获得基类的功能,而是为了类型匹配,达到多态的目的,获得功能由组合来实现。因此每一个装饰者都需要维护一个Beverage引用。

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 摩卡装饰者,为了能够取代Beverage,所以CondimentDecorator继承自Beverage,目的并非获得Beverage 5     /// 而是为了类型匹配 6     /// </summary> 7     public class Mocha : Beverage 8     { 9         //持有抽象类饮料的引用,达到运行时添加职责的目的10         Beverage beverage;11         //包装Beverage12         public Mocha(Beverage b, float price)13         {14             beverage = b;15             this.price = price;16         }17         public override float Cost()18         {19             return beverage.Cost() + price;20         }21 22         public override string GetDescription()23         {24             return beverage.GetDescription() + ", 摩卡";25         }26     }27 }

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 奶泡装饰者 5     /// </summary> 6     public class Whip : Beverage 7     { 8         private Beverage beverage; 9         public Whip(Beverage b, float price)10         {11             beverage = b;12             this.price = price;13         }14         public override float Cost()15         {16             return beverage.Cost() + price;17         }18         public override string GetDescription()19         {20             return (beverage.GetDescription() + " ,奶泡");21         }22     }23 }

 1 namespace DecoratorPattern 2 { 3     /// <summary> 4     /// 豆浆装饰者 5     /// </summary> 6     public class Soy : Beverage 7     { 8         private Beverage beverage; 9         public Soy(Beverage b, float price)10         {11             this.price = price;12             beverage = b;13         }14         public override float Cost()15         {16             return beverage.Cost() + price;17         }18 19         public override string GetDescription()20         {21             return( beverage.GetDescription() + ", 豆浆");22         }23     }24 }

客户端类:CoffeeShop.cs

 1 using System; 2  3 namespace DecoratorPattern 4 { 5     class CoffeeShop 6     { 7         static void Main(string[] args) 8         { 9             //来一杯浓缩咖啡,不要调料10             Beverage beverage = new Espresso(1.99f);11             Console.WriteLine(beverage.GetDescription() + "$" + beverage.Cost());12 13             //来一杯摩卡奶泡深焙咖啡14             Beverage beverage2 = new DarkRoast(0.99f);15             beverage2 = new Whip(beverage2, 0.1f);       //用奶泡装饰深焙咖啡16             beverage2 = new Mocha(beverage2, 0.2f);      //再用摩卡装饰17             Console.WriteLine(beverage2.GetDescription() + "$" + beverage2.Cost());18 19 20             Console.ReadKey();21         }22 23     }24 }

运行结果:

参考资料《Head First 设计模式》

原文出处:https://www.cnblogs.com/blackteeth/p/10212218.html 

作者:_清风明月 

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消