随感
可能是对继承的理解不是很透彻,也或者习惯了静态的定义和使用继承,今天刚看到装饰模式的时候,却是晕了好一会。
TerryLee的Blog中对装饰模式的引入和讨论真是思路清晰,精准到位,跟着他的思路,总算有点头绪。习惯了过程化编程的我,对于这种需求的变化,首先想到的肯定是改写实现方法体即可。但是通过这段时间学习设计模式和设计原则,我明白这样做的代价只能是维护和扩展的痛苦和艰难。所以,尝试着用OO的思想来冲洗我过程化的习惯,一时还真的觉得挺难接受。
引入
很显然,装饰模式的关键点在于对继承机制的动态应用。通常的继承使用方式(静态实现),在一些情况下显得有些臃肿,这个时候使用装饰模式可以动态搞定。
我设想了一个这样的场景:用户登陆控制。对于系统的登陆验证,我们可以根据具体的情况采用不同的登陆策略:测试阶段可以只根据用户名验证登陆;正式发布后要根据用户名和密码验证;如果有部门限制的话,还要结合部门信息进行权限验证。
在装饰模式中的各个角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。
例证
1.结构图
2.类的实现
3.客户端调用
例子分析
通过单步调试等手段,可以看出:由于具体装饰类都继承自装饰类,所以均拥有
那么我们在客户端进行参数传递后,实际上每个具体装饰类都对自己的CheckLogin变量进行了赋值。而后具体类中的base.Login();方法当然会执行到装饰类中去,而在装饰类中的Login方法引导此方法执行到实际传递进来的对象。
通过这样的设计,实际上实现了传递进来的对象就成了自己的父类对象,通过Base关键字实现方法的递归,从而达到动态继承,动态组合具体类的目的。
【实践】
还以WMS系统为例:最初我们的入库作业,只是进行了131,101入库抛转。后来由于业务需要,每个入库单据在入库时131,101抛转完成后,还要进行一个309转料号的动作。由于我们已经对之前的入库作业进行了抽象和封装,所以依据相关OO设计原则,新增加的动作也即【功能扩展】的部分以对象组合的方式进行。用在这个,我们就可以用装饰模式来对原来作业进行扩展。
部分代码:
}
}
SourceCode:/Files/Ivan-Yan/DecoratorPattern.rar
总结
最后引用TerryLee的精辟总结:
Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。
学习参考:
http://www.cnblogs.com/Terrylee/archive/2006/03/01/340592.html
http://www.cnblogs.com/zhenyulu/articles/46735.aspx
大话设计模式:装饰模式