我读设计模式之装饰模式(Decorator Pattern)
随感
可能是对继承的理解不是很透彻,也或者习惯了静态的定义和使用继承,今天刚看到装饰模式的时候,却是晕了好一会。
TerryLee的Blog中对装饰模式的引入和讨论真是思路清晰,精准到位,跟着他的思路,总算有点头绪。习惯了过程化编程的我,对于这种需求的变化,首先想到的肯定是改写实现方法体即可。但是通过这段时间学习设计模式和设计原则,我明白这样做的代价只能是维护和扩展的痛苦和艰难。所以,尝试着用OO的思想来冲洗我过程化的习惯,一时还真的觉得挺难接受。
引入
很显然,装饰模式的关键点在于对继承机制的动态应用。通常的继承使用方式(静态实现),在一些情况下显得有些臃肿,这个时候使用装饰模式可以动态搞定。
我设想了一个这样的场景:用户登陆控制。对于系统的登陆验证,我们可以根据具体的情况采用不同的登陆策略:测试阶段可以只根据用户名验证登陆;正式发布后要根据用户名和密码验证;如果有部门限制的话,还要结合部门信息进行权限验证。
在装饰模式中的各个角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。
例证
1.结构图
2.类的实现
class checkLogin //构件角色
{
public virtual void Login()
{
Console.WriteLine("-------------login successfully-----");
}
}
class loginDecorator : checkLogin //装饰角色
{
checkLogin CheckLogin;
public void setInstance(checkLogin checklogin)
{
this.CheckLogin = checklogin;
}
public override void Login()
{
CheckLogin.Login();
}
}
class pwdCheckLogin : loginDecorator //具体装饰角色
{
public override void Login()
{
Console.WriteLine("Login with password");
base.Login();
}
}
class UserPwdCheckLogin : loginDecorator //具体装饰角色
{
public override void Login()
{
Console.WriteLine("Login with username");
base.Login();
}
}
class DeptCheckLogin : loginDecorator //具体装饰角色
{
public override void Login()
{
Console.WriteLine("Login with Dept information");
base.Login();
}
}3.客户端调用
static void Main(string[] args)
{
checkLogin check = new checkLogin();
pwdCheckLogin pwd = new pwdCheckLogin();
UserPwdCheckLogin user = new UserPwdCheckLogin();
DeptCheckLogin dept = new DeptCheckLogin();
//用户名和密码一起验证
Console.WriteLine("第一种方式");
pwd.setInstance(check);
user.setInstance(pwd);
user.Login();
//用户名,密码和部门信息一起验证
Console.WriteLine("第二种方式");
pwd.setInstance(check);
user.setInstance(pwd);
dept.setInstance(user);
dept.Login();
}例子分析
通过单步调试等手段,可以看出:由于具体装饰类都继承自装饰类,所以均拥有
checkLogin CheckLogin;
public void setInstance(checkLogin checklogin)
{
this.CheckLogin = checklogin;
}那么我们在客户端进行参数传递后,实际上每个具体装饰类都对自己的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
大话设计模式:装饰模式


浙公网安备 33010602011771号