装饰模式与大接口的装饰模式的思考

    装饰模式作为一个比较常见的模式,我就不再细说了,并且在.net框架中也多次出现(例如全透明装饰类BufferedStream与它的基类Stream)
    此外,另一个比较有趣的例子大家可能不太会用到,这次被装饰的Type这个类型,装饰者是TypeDelegator。
    Type这个类型本身比较复杂,大大小小的实例成员加起来不下100个(包括继承的),其中可覆盖的核心方法有也有50多个。如果需要装饰一下Type的话,那么至少这50多个成员需要被覆盖,而需求可能仅仅只是为了监视某一个属性。这使得手段和目的显得极为不对称。
    面对这样的需求,M$提供了这么一个TypeDelegator类型来作为对Type装饰的基类,具体的装饰类只要再次覆盖其中的几个特定的方法就可以了。
    这时候,应该可以想到,装饰模式中的基础接口应该尽量的轻,像Type这样的重型类似乎不太合适。但是有的时候显然有是需要装饰一下这种重型类。比如说,如果希望在反射某一个Type的时候,当取这个类型的所有实例方法(Type.GetMethod(BindingFlag.Instance))的时候记录一下日志。这样的需求似乎摆明了要用装饰模式。假设没有TypeDelegator类型(或者不知道它的存在 ),在装饰Type的时候,估计就会火冒三丈的大骂M$,怎么在Type里面放了这么多垃圾方法,或者再找其他的手段来达到这个目的。

    下面进入正题:大接口怎么装饰?
    这里说的大接口(这里的接口是泛意的接口)是指需要覆盖的成员不下20个,而真正需要装饰的成员仅仅是很小一部分。这样要么和M$一样,建一个装饰基类。但是如果仅仅只有一个装饰类,岂不是很浪费。
    那么第二条路是什么?经过漫长的思考,我觉得如果将大接口限定为狭义接口(interface,不包含抽象类等)的话,可以通过Emit技术来生成这么一个动态装饰类。
    问题是:哪些成员需要装饰?这些成员怎么装饰?Debug怎么办?怎样半透明装饰?
    经过否决N个方案后,终于找到了可行的方案。用到的核心技术依然是.net的四大神器:泛型、反射、特性、Emit。其中特性是可选的,通过配置注入也是完全可行的。
    方案的核心手段是建立一个混入类(Mixin),这个混入类的职责是告诉动态装饰工厂如何装饰,并且需要绝对实现半透明的部分。
    举个例子来说吧:
    原始接口:
     public   interface  ISource
    {
        
void  HelloWorld();
        
string  Name {  get set ; }
        
    }

    装饰接口:
     public   interface  IDecorator
        : ISource
    {
        
event  EventHandler NameChanged;
    }

    混入类:
    [DecoratorMixinType( typeof (ISource),  typeof (IDecorator))]
    
public   class  DecoratorMixin
    {

        
private  ISource _src;
        
private  IDecorator _decorator;

        
public  DecoratorMixin(ISource src, IDecoratorForTest decorator)
        {
            _src 
=  src;
            _decorator 
=  decorator;
        }

        [DecoratorMixinProperty()]
        
public   string  Name
        {
            
get  {  return  _src.Name; }
            
set
            {
                
if  (value  !=  _src.Name)
                {
                    _src.Name 
=  value;
                    OnNameChanged(EventArgs.Empty);
                }
            }
        }

        
protected   virtual   void  OnNameChanged(EventArgs e)
        {
            
if  (NameChanged  !=   null )
                NameChanged(_decorator, e);
        }

        [DecoratorMixinEvent()]
        
public   event  EventHandler NameChanged;
    }


    再来看一下ISource的实现:
     public   sealed   class  SrcImpl
        : ISource
    {

        
#region  Fields
        
private   string  _name;
        
        
#endregion

        
#region  Ctors

        
public  SrcImpl()
        {
            _name 
=   this .ToString();
            
        }

        
#endregion

        
#region  ISrcForTest Members

        
public   void  HelloWorld()
        {
            Console.WriteLine(
" Hello world, my name is {0}. " , Name);
        }

        
public   string  Name
        {
            
get  {  return  _name; }
            
set  { _name  =  value; }
        }
        
        
#endregion
    }

    最后,看一下客户端的调用:
     class  Program
    {
        
static   void  Main( string [] args)
        {
            ISource src 
=   new  SrcImpl();
            IDecorator decorator 
=  DecoratorFactory.Create < ISource, IDecorator, DecoratorMixin > (src);
            decorator.HelloWorld();
            decorator.NameChanged 
+=   new  EventHandler(decorator_NameChanged);
            decorator.Name 
=   " Name2 " ;
            decorator.HelloWorld();
            Console.ReadLine();
        }

        
static   void  decorator_NameChanged( object  sender, EventArgs e)
        {
            IDecorator decorator 
=  sender  as   IDecorator;
            Console.WriteLine(
" I'm \ " Program\ " , some one told me, the source changed it's name to {0} " , decorator.Name);
        }
    }


    来看一下最终结果:

Hello world, my name  is  TestDynamicDecorator.SrcImpl.
I
' m "Program", some one told me, the src changed it ' s name to New Name
Hello world, my name 
is  New Name.

    在这里,魔术师就是 DecoratorFactory.Create < ISource, IDecorator, DecoratorMixin >,它负责变出一个匿名类来实现 IDecorator,并且将其中的Name属性绑定的方法和NameChanged事件绑定的方法覆盖为调用混入类的方法,而其他方法(例如HelloWorld方法)就直接调用ISource对象的方法。
    (目前这个
DecoratorFactory还未完成,主要是容错方面的问题,完成后将集成到ZForce中一齐发布


你可能感兴趣的:(装饰模式)