您好,欢迎来到我要学flash网!登录注册

【AS3与设计模式】 Decorator Pattern (装饰者模式)

来源:我要学flash网 | 作者:admin | 发表时间:2011-07-11 | 点击:  次

[arrow] 关于这一系列的索引页和说明请点这里 http://www.nshen.net/blog/article.asp?id=510

[arrow] 直接下Decorator Pattern演示代码的点这里

先看一下定义:

The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flash.com/article/flex' target='_blank'>flexible alternative to subclassing for extending functionality 。

大概意思就是说

装饰者模式可以动态地给一个对象增加其他职责。装饰者模式提供一个比继承更灵活方法扩展对象的功能。

什么是动态和静态呢? 简单的说,就是静态对应继承,比如现在有一个类,现在想给其增加一些方法,静态的办法就是写一个类 extends 原来的类,在其中扩展一些方法,而动态对应组合 同样的问题动态的办法就是在runtime时运用组合给类增加方法。随便找本oo的书肯定有写组合比继承灵活,翻出来看看吧。

看一下怎么动态增加职责的:

  1. //比如原来有一个类起名叫ConcreteComponent  
  2.  var concreteComponent:ConcreteComponent=new ConcreteComponent();  
  3.  
  4. //ConcreteComponent有一个operation的方法,只是简单的trace  
  5.  concreteComponent.operation() //trace: 原始行为  
  6.  
  7.  //下面开始扩展原始的行为了,声明一个新装饰器叫做ConcreteDecoratorA ,把原来的concreteComponent给装饰一下~  
  8.  var concreteDecoratorA:ConcreteDecoratorA= new ConcreteDecoratorA(concreteComponent)  
  9.  
  10.  //现在再调用operation方法吧(扩展了装饰之前的operation方法)  
  11.  concreteDecoratorA.operation()  
  12.  //trace: 原始行为 经过ConcreteDecoratorA装饰!  
  13.  
  14.  //下面再重新装饰一个新行为  
  15.  var concreteDecoratorB:ConcreteDecoratorB=new ConcreteDecoratorB(concreteComponent)  
  16.  //这回经过装饰后,出现了新的方法叫newOperation  
  17.  concreteDecoratorB.newOperation()   
  18.  //trace: 被装饰的新行为 newOperation()方法  
  19.  

该看看具体是怎么实现的了

类图到现在我还不会画,不过谷哥就是强,随便一搜就找到类图了
attachments/200709/05_141427_decorator.gif

附加一个《head first design pattern》 里的图
attachments/200709/05_144530_decorator2.jpg
Decorator跟Component之间的关系解释
 

引用
Decorator是装饰者模式里非常特殊的一个类,它既继承于Component【IS A关系】,又维护一个指向Component实例的引用【HAS A关系】,换个角度来说,Decorator跟Component之间,既有动态组合关系又有静态继承关系,WHY? 这里为什么要这么来设计?上面我们说过,组合的好处是可以在运行时给对象增加职责,Decorator【HAS A】Component的目的是让ConcreteDecorator可以在运行时动态给ConcreteComponent增加职责,这一点相对来说还比较好理解;那么Decorator继承于Component的目的是什么?在这里,继承的目的只有一个,那就是可以统一装饰者和被装饰者的接口,换个角度来说,不管是ConcretComponent还是ConcreteDecorator,它们都是 Component,用户代码可以把它们统一看作Component来处理,这样带来的更深一层的好处就是,装饰者对象对被装饰者对象的功能职责扩展对用户代码来说是完全透明的,因为用户代码引用的都是Component,所以就不会因为被装饰者对象在被装饰后,引用它的用户代码发生错误,实际上不会有任何影响,因为装饰前后,用户代码引用的都是Component类型的对象,这真是太完美了!装饰者模式通过继承实现统一了装饰者和被装饰者的接口,通过组合获得了在运行时动态扩展被装饰者对象的能力。

//上边这段话转自某文章,地址找不到了抱歉 [sad]

各个部分:

Component(被装饰对象基类) 一个抽象类或接口
 

  1. package net.nshen.designpatterns.decorator  
  2. {  
  3.   public class Component  
  4.   {  
  5.     public function operation():void{    
  6.     }  
  7.   }  
  8. }  


ConcreteComponent(具体被装饰对象) 定义具体的对象,Decorator可以给它增加额外的职责;
 

  1. package net.nshen.designpatterns.decorator  
  2. {  
  3.   //被装饰者  
  4.   public class ConcreteComponent extends Component  
  5.   {  
  6.     override public function operation():void{  
  7.      trace("原始行为")  
  8.     }  
  9.   }  
  10. }  


Decorator(装饰者抽象类) 维护一个指向Component实例的引用(这个实例就是要被装饰的对象),并且定义了与Component一致的接口;
 

  1. package net.nshen.designpatterns.decorator  
  2. {  
  3.   public class Decorator extends Component  
  4.   {  
  5.     //被装饰者  
  6.     private var _component:Component  
  7.       
  8.     public function Decorator(p_component:Component):void{  
  9.      this._component=p_component;  
  10.     }  
  11.       
  12.     override public function operation():void{  
  13.      this._component.operation()  
  14.     }  
  15.   }  
  16. }  


ConcreteDecorator(具体装饰者) 具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责

扩展现有的方法
 

  1. package net.nshen.designpatterns.decorator  
  2. {  
  3.   public class ConcreteDecoratorA extends Decorator  
  4.   {  
  5.     public function ConcreteDecoratorA(p_component:Component)  
  6.     {  
  7.       super(p_component);  
  8.     }  
  9.      override public function operation():void{  
  10.      super.operation()  
  11.      trace("经过ConcreteDecoratorA装饰!")  
  12.     }  
  13.   }  
  14. }  


增加新方法
 

  1. package net.nshen.designpatterns.decorator  
  2. {  
  3.   public class ConcreteDecoratorB extends Decorator  
  4.   {  
  5.     public function ConcreteDecoratorB(p_component:Component)  
  6.     {  
  7.       super(p_component);  
  8.     }  
  9.     //装饰新行为  
  10.     public function newOperation():void{  
  11.      trace("被装饰的新行为 newOperation()方法")  
  12.     }  
  13.       
  14.   }  
  15. }  


最后看一下目前为止的测试类designpattern.as吧
 

  1. package {  
  2.   import flash.display.Sprite;  
  3.  import net.nshen.designpatterns.strategy.*;  
  4.  import net.nshen.designpatterns.decorator.*;  
  5.  import net.nshen.designpatterns.singleton.Singleton;  
  6.    
  7.    
  8.   public class designpatterns extends Sprite  
  9.   {  
  10.     public function designpatterns()  
  11.     {  
  12.       //Test_Strategy()  
  13.       //Test_Singleton()  
  14.  
  15.       Test_Decorator()  
  16.     }  
  17.       
  18.       
  19.     public function Test_Strategy():void{  
  20.      var context:Context=new Context();  
  21.      //设置策略  
  22.      context.strategy=new ConcreteStrategyA()  
  23.      context.ContextInterface()  
  24.      //runtime 更改策略B  
  25.      context.strategy=new ConcreteStrategyB()  
  26.      context.ContextInterface()  
  27.      //runtime 更改策略C  
  28.      context.strategy=new ConcreteStrategyC()  
  29.      context.ContextInterface()  
  30.     }  
  31.       
  32.     public function Test_Decorator():void{  
  33.      var concreteComponent:ConcreteComponent=new ConcreteComponent();  
  34.      concreteComponent.operation()  
  35.      //扩展原始的行为  
  36.      var concreteDecoratorA:ConcreteDecoratorA= new ConcreteDecoratorA(concreteComponent)  
  37.      concreteDecoratorA.operation()  
  38.      //装饰新行为  
  39.      var concreteDecoratorB:ConcreteDecoratorB=new ConcreteDecoratorB(concreteComponent)  
  40.      concreteDecoratorB.newOperation()  
  41.     }  
  42.       
  43.     public function Test_Singleton():void{  
  44.      var s:Singleton=Singleton.getInstance()  
  45.      s.doSomething();  
  46.      /*  
  47.      使用构造函数创建实例会报错  
  48.      var s1:Singleton=new Singleton()  
  49.      s1.doSomething()  
  50.      */ 
  51.     }  
  52.       
  53.       
  54.   }  
  55. }  


[arrow] 完整代码下载点这里

=================理论与实践分割线=========================================================

实践1:实现 IEventDispatcher接口来进行事件发送。

这个例子我是在kingda的blog上发现了的,感谢一下他,原文地址
http://www.kingda.org/archives/kingda/2006/08/as30106.html

以下是原文末端部分节选的

引用
类可能是因为本身已经继承了其它类,无法再继承EventDispatcher。
而我们恰恰希望它能实现EventDispatcher类所有功能,比如说addEventListener, hasListener等等,看起来简直和继承EventDispatcher没什么分别。
那么OK,我建议使用 实现IEventDispatcher接口来进行事件发送。
其实质是一个装饰器模式(Decorator),以对客户端透明的方式扩展对象功能,是继承关系的一个替代方案。其关键在于扩展是完全透明的,使用起来和继承父类几乎没什么区别。

具体方法
由于IEventDispatcher需要实现5个接口,addEventListener, hasListener, willTrigger,removeEventListener,hasEventListener,那么我们的装饰类也必须实现这五个接口。
其余看代码

优点:
1.类的用户完全感觉不到差别
2.在被包装的方法中还可以加入其它自己希望加进去的动作,比如,在addEventListenr方法中可以再插入一个计数,看看到底被add了多少次,超过某些次后,调用某个方法等等。
总而言之,给我们带来了极大的灵活性。这就是装饰器模式的好处。
  1. package {  
  2.  import flash.display.Sprite;  
  3.  import flash.events.Event;  
  4.  import flash.events.MouseEvent;   
  5.  import flash.events.EventDispatcher;  
  6.    
  7.  public class LearnDecoratorEvents extends Sprite {  
  8.     public function LearnDecoratorEvents() {  
  9.         
  10.       var kingdaObj:KingdaClass = new KingdaClass();  
  11.       kingdaObj.addEventListener(KingdaClass.ACTION, lisFunc); //用起来和EventDispatcher对象一样哦,呵呵。  
  12.         
  13.       var evtObj:Event = new Event(KingdaClass.ACTION);  
  14.       kingdaObj.dispatchEvent(evtObj);//确实一样吧 :)  
  15.       //输出:listened:yeahyeah  
  16.     }  
  17.       
  18.     private function lisFunc(evtObj:Event):void {  
  19.       trace ("listened:"+evtObj.type);  
  20.     }  
  21.   }  
  22.   import flash.events.IEventDispatcher;  
  23.   import flash.events.EventDispatcher;  
  24.   import flash.events.Event;  
  25.  
  26.   class KingdaClass implements IEventDispatcher{  
  27.     public var _dispatcher:EventDispatcher;  
  28.     public static const ACTION:String = "yeahyeah";  
  29.       
  30.     public function KingdaClass() {  
  31.       // other ....  
  32.       initSender();  
  33.     }  
  34.       
  35.     private function initSender():void {  
  36.       _dispatcher = new EventDispatcher(this);  
  37.     }  
  38.  //哈哈,在实现接口时还可以乘机干点别的,比如我喜欢吧useWeakReference设为true  
  39.    public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void{  
  40.    // do other things;  
  41.    _dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);  
  42.     }  
  43.    
  44.    public function dispatchEvent(evt:Event):Boolean{  
  45.    // do other things;  
  46.       return _dispatcher.dispatchEvent(evt);  
  47.    }  
  48.    
  49.    public function hasEventListener(type:String):Boolean{  
  50.       // do other things;  
  51.  return _dispatcher.hasEventListener(type);  
  52.    }  
  53.    
  54.    public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void{  
  55.    // do other things;  
  56.     _dispatcher.removeEventListener(type, listener, useCapture);  
  57.    }  
  58.    
  59.    public function willTrigger(type:String):Boolean {  
  60.    // do other things;  
  61.     return _dispatcher.willTrigger(type);  
  62.    }  
  63.   }  
  64. }  


实践2 :
听iiley说aswing里的Border是用Decorator设计的,有兴趣的可以看看,俺aswing没细学过,Border是做什么的都不知道,以后再研究
,仍然是有例子的跟我联系,或者留言,谢谢了

    顶一下
    (0)
    0%
    踩一下
    (0)
    0%
    本文引用地址:
      最新评论: 共有位网友发表了评论
      发表评论:
    请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
    评价:
    表情:
    用户名: 密码: 验证码: