我读设计模式之装饰模式(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设计原则,新增加的动作也即【功能扩展】的部分以对象组合的方式进行。用在这个,我们就可以用装饰模式来对原来作业进行扩展。
      部分代码:

 

Code


      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

     大话设计模式:装饰模式

 

posted on 2008-07-23 11:41  easy2Dev  阅读(298)  评论(0)    收藏  举报

导航