该文章综合了几本书的内容.
某咖啡店项目的解决方案某咖啡店供应咖啡, 客户买咖啡的时候可以添加若干调味料, 最后要求算出总价钱.
Beverage是所有咖啡饮料的抽象类, 里面的cost方法是抽象的. description变量在每个子类里面都需要设置(表示对咖啡的描述).
每个子类实现cost方法, 表示咖啡的价格.
除了这些类之外, 还有调味品:
问题是调味品太多了, 如果使用继承来做的话, 各种组合简直是类的爆炸.
而且还有其他的问题, 如果牛奶的价格上涨了怎么办? 如果再加一种焦糖调料呢?
另一种解决方案父类里面有调味料的变量(bool), 并且在父类里面直接实现cost方法(通过是否有某种调味料来计算价格).
子类override父类的cost方法, 但是也调用父类的cost方法, 这样就可以把子类这个咖啡的价格和父类里计算出来的调味料的价格加到一起算出最终的价格了.
下面就是:
看起来不错, 那么, 问题来了:
调味料价格变化的话就不得不修改现有代码了
如果有新的调味料那么久必须在父类里面添加新的方法, 并且修改cost方法了.
可能某些调味料根本不适用于某些咖啡
如果某个客户想要两个摩卡(调味料)怎么办?
设计原则类应该对扩展开放 而对修改关闭.
装饰模式使用装饰模式, 我们可以购买一个咖啡, 并且在运行时使用调味料对它进行装饰.
大约步骤如下:
买某种咖啡
使用mocha调味料装饰它
使用whip调味料装饰它
调用cost方法, 并且使用委托来计算调味料的总价格
到目前我知道了这些:
装饰器的父类和它所要装饰的对象的父类是一样的
可以使用多个装饰器来装饰某对象
既然装饰器和被装饰对象的父类是一样的, 那传递的时候就传递被装饰过的对象就好了.
装饰器会在委托给它要装饰的对象之前和/或之后添加自己的行为以便来完成余下的工作.
对象可以在任意时刻被装饰, 所以可以在运行时使用任意多个装饰器对对象进行装饰.
装饰模式定义动态的对某个对象进行扩展(附加额外的职责), 装饰器是除了继承之外的另外一种为对象扩展功能的方法.
下面看看该模式的类图:
重新设计这个就很好理解了, 父类都是Beverage(饮料), 左边是四种具体实现的咖啡, 右边上面是装饰器的父类, 下面是具体的装饰器(调味料).
这里需要注意的是, 装饰器和咖啡都继承于同一个父类只是因为需要它们的类型匹配而已, 并不是要继承行为.
.NET Core 代码实现Beverage:
namespace DecoratorPattern.Core { public abstract class Beverage { public virtual string Description { get; protected set; } = "Unknown Beverage"; public abstract double Cost(); } }