看到上次写到了策略模式,最近又浏览了各位大神的博客,发现自己身边真的是卧虎
藏龙啊,各个都写的那叫一绝,感到很欣慰,可以从他们身上借鉴一下知识。在这期间
也学习了几个原则,先简单的总结一下这几个原则的用法。
单一职责原则:充分发挥GTD时间管理的思想,尽量使一个类的单一化。
开放—封闭原则:扩展改进需求,不可修改源代码。、
依赖倒转原则:依赖抽象编程,这里的抽象指的是接口或者抽象类。
在学习这几个原则之后,自己也感悟到了几句话在此与大家分享一下。
1. 做软件就是要找到系统中变化的部分,然后将变化的部分与稳定的部分隔离
2. 要面对接口编程,而不要面对实现编程
3. 优先使用对象组合,而非继承
好了接下来就进入我们今天的正题—装饰者模式
今天我们会从一个故事开始,来聊一聊什么是装饰者模式,它有什么特点,并会演示
一个简单而有趣的例子,最后会进行相关的汇总和总结。
奶茶店
如果根据一家奶茶店来设计类图,那么又该如何设计呢?以下是小编初想。
这是最初的设想,让Beverage作为所有饮料的基类,然后所有的子类调用基类的Cost
方法即可,这种方法可以满足当前的需求,可是忘了一回事-调味品。
有的人喜欢往饮料里面添加自己的调味品,比如糖、牛奶等,那么这又该怎么办呢?总
不会把所有的种类都列出来吧(再说这也不可能,加一块糖也算一类话,根本就全部列
不出来),先别说可行性,如果列出来的话,那么这个类该有多么的强大啊。
接下来小编又想到了一个办法,把调味品作为基类的布尔变量加入,然后通过Set或
者get来给变量赋值,其次在基类Cost实现调味品的价格,子类覆盖基类的cost方法,只
是需要调用基类的Cost方法以便来获得调味品的价格
看上去不错,真的就完事大吉了吗?回顾我刚开始提到的几个原则—把系统中变化的
部分与稳定的部分进行隔离,那么我们分析下奶茶店那些会变化,奶茶种类会变化吗?
调味品的价格和种类会变化吗?YES,对于一家奶茶店来说,奶茶种类肯定会变化的,没
事,到时候我们只需要增加子类即可。如果顾客加了两块糖和牛奶又该如何呢?我发现
设计的类图竟然不能满足上述需求,因为上述类图只能判断是否有某种调味品存在但并
不能实现几份的问题,那么又该如何是好呢?
那么就接着看看我们今天的主角—装饰模式
定义:
动态的给对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
Component(被装饰对象基类)
定义对象的接口,可以给这些对象动态增加职责
ConcreteComponent(具体被修饰对象)
定义具体的对象,Decorator可以给它增加额外的职责
Decorator(装饰者抽象类)
维护一个指向Component实例的引用,并且定义了与Component一致的接口
ConcreteDecorator(具体装饰者)
具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责。
什么叫做动态增加职责
所谓动态是说可以在系统运行时动态给对象增加其他职责而不需要修改代码或重新
编译;所谓静态,说必须通过调整代码才能给对象增加职责,而且系统还需要重新编
译;其实对象的组合和继承刚好对应于前面的动态和静态。因此我们在以后的编程中应
该多使用组合来保持系统运行时的扩展性,尽量少使用继承,因为它有点僵硬。
下面是经过改变后的类图
如图Beverage是所有的饮料的基类,而牛奶咖啡和苹果奶茶是具体的对象,而
ConcreteDecorator是要修饰的抽象类,而具体的调味品继承了它,下面看代码的实现部
分。
//饮料基类
public abstract class Beverage
{
public virtual string GetDescription()
{
return "Unknow Beverage";
}
public abstract double cost();
}
//香蕉奶茶
public class BananaMilkTea : Beverage
{
public override double cost()
{
return 0.99;
}
}
//红豆奶茶
public class RedBeanmilkTEA : Beverage
{
public override double cost()
{
return 1.5;
}
}
//调味品类
public abstract class CondimentDecorator:Beverage
{
}
//加糖
public class soy : CondimentDecorator
{
Beverage beverage;
public soy(Beverage beverage)
{
this.beverage = beverage;
}
public override double cost()
{
return 0.45 +beverage.cost() ;
}
}
}
至于代码应该没没什么好解释的了,上面的类图解释的已经很清楚了。看客户端的实
现部分。
//先实例化一杯香蕉奶茶
Beverage beverage = new BananaMilkTea();
//为香蕉奶茶加佐料
soy pqx = new soy(beverage);
Console.WriteLine(pqx.cost());
以上就是所谓的装饰模式,其实就是抽象出动态要装饰的部分,也就是要动态添加功能的部分,然后通过具体的方式来修饰对象。这种方式把类固定的部分和要动态添加的部分割裂开来,这样就大大简化了原始的类的结构。
正所谓“金无足赤,人无完人”,模式也不是全能的,我们要熟知什么情况下要用
它,也就是应用场景的问题。
装饰者模式的应用场景:
1、动态给对象增加新的职责的时候
2.给对象增加的职责,在未来存在增加或减少可能
【备注:关于场景,上面肯定说的不全,欢迎大家来补充。】