《Head First Design Patterns》笔记三:装饰者模式(Decorator Pattern)
2009-04-14 15:34
537 查看
前言
什么是装饰呢,通俗来说,人靠衣装,佛靠金装,这里呢,人就是被装饰者,衣服就是装饰品,你穿再多衣服,性质没变,还是个人啦,你还是可以再戴上新戒指,而不必关心这人之前穿了什么衣服.
引申到软件工程里呢,就是一个已存在的类,可能需要不断的增加新功能,那么我们新建新功能 当做装饰品,装饰现有的类,而不必要去不断修改已有的代码,要知道碰旧代码通常是一件让人头疼的事情.这符合设计模式的一个原则:对扩展开放,而对修改关闭.就是说有新功能我们尽量在外部扩展用新代码,而不是去内部修改旧的代码,把新功能加进去.ok,闲话少说,言归正传,我们这里以一个咖啡店作为例子来讲解这个装饰者模式.
需求
新业务上门了,现在我们需要为一家咖啡店做买单系统,咖啡店提供的咖啡有espresso(浓缩咖啡) ,houseblend(家常咖啡),配料有 peppermint syrup(薄荷汁),milk(牛奶),soy(豆浆),mocha(摩卡,就是里面加巧克力),whipped milk(奶泡,会浮在上面的那种热牛奶,泡沫状),1种咖啡,加任意1种或多种配料就可以组合成几十上百种咖啡了
初步设计
我们当然可以去玩排列组合的把戏,把所有能组成的咖啡都去做1个类,那就是个类炸弹,把我们会炸晕的. so我们考虑把配料作为成员,放在咖啡类里面.设计如图
参考以上uml图表,有加牛奶的话,就设置hasMilk为true.加豆浆的话就设置hasSoy为true,这样就很容易实现需求,但是问题来了,一旦有了新的配料呢, 那么我们就不得的不修改coffee类了,如果用户不只要1份milk,而是要double呢,这些后期维护问题使得我们不断的修改原有的代码,这破坏了类的封装,违反了我们的设计原则,尽量对扩展开放,而不是对修改开放.
进一步设计
我们考虑装饰者模式,客户可以在运行时动态的增添功能,而不是在编译的时候去增添功能.这样的设计十分灵活.如下图.
再回头考虑咖啡店,把咖啡作为ConcreteComponent,把调料作为DecoratorComponent,咖啡加入任何调料,还是一杯咖啡,继续增添新调料的话,不需要关心前面已经加入了哪种调料,有新的调料加入时,只需要增加一个新的调料的类,其他代码不需要做任何修改.uml作图如下
代码
剩下的就是代码实现了, 这里把代码分为9个类,
首先是3个类,IBerverage接口,Espresso类,HouseBlend类,如下:
然后是扮演装饰角色的5个类,包括IDecoratorBeverage虚类,Milk类,Mint类,Soy类,Whip类
如下:
最后就是测试运行代码了 Program.cs 如下:
运行结果:
Espresso:$10
Espresso Soy Whip:$12.5
HouseBlend Mint Milk Milk:$14.5
总结
装饰者模式就是可以动态的将组件添加到已有的类中,以实现新功能。我们在实际编程中遇见需求更改,添加新功能的时候经常用到这个模式,这也符合面向对象的一个设计原则:尽量使用组合,而不是继承。
下一篇:《Head First Design Patterns》笔记四:工厂模式(Factory Pattern)
上一篇:《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)
什么是装饰呢,通俗来说,人靠衣装,佛靠金装,这里呢,人就是被装饰者,衣服就是装饰品,你穿再多衣服,性质没变,还是个人啦,你还是可以再戴上新戒指,而不必关心这人之前穿了什么衣服.
引申到软件工程里呢,就是一个已存在的类,可能需要不断的增加新功能,那么我们新建新功能 当做装饰品,装饰现有的类,而不必要去不断修改已有的代码,要知道碰旧代码通常是一件让人头疼的事情.这符合设计模式的一个原则:对扩展开放,而对修改关闭.就是说有新功能我们尽量在外部扩展用新代码,而不是去内部修改旧的代码,把新功能加进去.ok,闲话少说,言归正传,我们这里以一个咖啡店作为例子来讲解这个装饰者模式.
需求
新业务上门了,现在我们需要为一家咖啡店做买单系统,咖啡店提供的咖啡有espresso(浓缩咖啡) ,houseblend(家常咖啡),配料有 peppermint syrup(薄荷汁),milk(牛奶),soy(豆浆),mocha(摩卡,就是里面加巧克力),whipped milk(奶泡,会浮在上面的那种热牛奶,泡沫状),1种咖啡,加任意1种或多种配料就可以组合成几十上百种咖啡了
初步设计
我们当然可以去玩排列组合的把戏,把所有能组成的咖啡都去做1个类,那就是个类炸弹,把我们会炸晕的. so我们考虑把配料作为成员,放在咖啡类里面.设计如图
参考以上uml图表,有加牛奶的话,就设置hasMilk为true.加豆浆的话就设置hasSoy为true,这样就很容易实现需求,但是问题来了,一旦有了新的配料呢, 那么我们就不得的不修改coffee类了,如果用户不只要1份milk,而是要double呢,这些后期维护问题使得我们不断的修改原有的代码,这破坏了类的封装,违反了我们的设计原则,尽量对扩展开放,而不是对修改开放.
进一步设计
我们考虑装饰者模式,客户可以在运行时动态的增添功能,而不是在编译的时候去增添功能.这样的设计十分灵活.如下图.
再回头考虑咖啡店,把咖啡作为ConcreteComponent,把调料作为DecoratorComponent,咖啡加入任何调料,还是一杯咖啡,继续增添新调料的话,不需要关心前面已经加入了哪种调料,有新的调料加入时,只需要增加一个新的调料的类,其他代码不需要做任何修改.uml作图如下
代码
剩下的就是代码实现了, 这里把代码分为9个类,
首先是3个类,IBerverage接口,Espresso类,HouseBlend类,如下:
//file 1:Iberverage.cs using System; public interface IBeverage { string Description{get;} double Cost(); } //file 2:Espresso.cs using System; public class Espresso:IBeverage { public string Description { get{return "Espresso";} } public double Cost() { return 10; } } //file 3:HouseBlend.cs using System; public class HouseBlend:IBeverage { public string Description { get{return "HouseBlend";} } public double Cost() { return 8; } }
然后是扮演装饰角色的5个类,包括IDecoratorBeverage虚类,Milk类,Mint类,Soy类,Whip类
如下:
//file 1 DecoratorBeverage.cs using System; public abstract class DecoratorBeverage:IBeverage { public abstract string Description{get;} public abstract double Cost(); } //file 2 Milk.cs using System; public class Milk:DecoratorBeverage { private IBeverage beverage; public override string Description { get{return beverage.Description+" Milk";} } public Milk(IBeverage beverage) { this.beverage=beverage; } public override double Cost() { return beverage.Cost()+2; } } //file 3 Mint.cs using System; public class Mint:DecoratorBeverage { private IBeverage beverage; public override string Description { get{return beverage.Description+" Mint";} } public Mint(IBeverage beverage) { this.beverage=beverage; } public override double Cost() { return beverage.Cost()+2.5; } } //file 4 Soy.cs using System; public class Soy:DecoratorBeverage { private IBeverage beverage; public override string Description { get{return beverage.Description+" Soy";} } public Soy(IBeverage beverage) { this.beverage=beverage; } public override double Cost() { return beverage.Cost()+1; } } //file 5 Whip.cs using System; public class Whip:DecoratorBeverage { private IBeverage beverage; public override string Description { get{return beverage.Description+" Whip";} } public Whip(IBeverage beverage) { this.beverage=beverage; } public override double Cost() { return beverage.Cost()+1.5; } }
最后就是测试运行代码了 Program.cs 如下:
using System; public class Program { public static void Main() { IBeverage beverage1=new Espresso(); IBeverage beverage2=new Whip(new Soy(new Espresso())); IBeverage beverage3=new Milk(new Milk(new Mint(new HouseBlend()))); Console.WriteLine(beverage1.Description+":$"+beverage1.Cost()); Console.WriteLine(beverage2.Description+":$"+beverage2.Cost()); Console.WriteLine(beverage3.Description+":$"+beverage3.Cost()); } }
运行结果:
Espresso:$10
Espresso Soy Whip:$12.5
HouseBlend Mint Milk Milk:$14.5
总结
装饰者模式就是可以动态的将组件添加到已有的类中,以实现新功能。我们在实际编程中遇见需求更改,添加新功能的时候经常用到这个模式,这也符合面向对象的一个设计原则:尽量使用组合,而不是继承。
下一篇:《Head First Design Patterns》笔记四:工厂模式(Factory Pattern)
上一篇:《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)
相关文章推荐
- 《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)
- 《Head First Design Patterns》笔记八:外观模式(Facade Pattern)
- 《Head First Design Patterns》笔记一:策略模式(Strategy Pattern)
- 《Head First Design Patterns》笔记六:命令模式(Command Pattern)
- OOP Design (Head First Design Patterns) 学习笔记--04 The decorator pattern
- 《Head First Design Patterns》笔记四:工厂模式(Factory Pattern)
- 装饰者模式——Head First Design Patterns
- HeadFirst design pattern笔记-装饰者模式
- 装饰者模式--《Head First DesignPattern》
- 《Head First Design Patterns》笔记九:模版模式(Template Method Pattern)
- Head First Design Patterns 阅读笔记之六: Command Pattern
- 解释器模式——Head First Design Patterns
- Head First Design Patterns - Iterator Pattern
- 《Head First Design Patterns》读书笔记之模板模式
- Head First Design patterns笔记-Decorator Patterns (从”用不同技能武装自己”看装饰模式)
- 设计模式之 观察者模式 the observer design pattern ---------《head first design pattern》
- 《Head First Design Patterns》读书笔记之单例模式
- 设计模式-读书笔记-on Head First Design Pattern
- 《Head First Design Patterns》笔记十二:状态模式(State Pattern)