设计模式之-装饰模式

来源:互联网 发布:一句话证明你了解java 编辑:程序博客网 时间:2024/04/27 14:51

装饰的含义就是在原有的物件上增加饰品,使得物件能呈现出不同的特征。当然在类设计中,采用装饰模式,是用来为类增加新的特征和行为。结构如下:

    *  
  *                   | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|                               
  *                   |     Component           |<-------------------------------------------------------------------| 
  *                   |----------------------- -----|                                                                                       |
  *                   | Operation()               |                                                                                       |                     
  *                   |________________|                                                                                        |
  *                                   △                                                                                                        |
  *                                     |                                                                                                          |
  *                     | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|                                                 |    
  * | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|           | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|◇-Component------|
  * |  ConcreateComponent       |           |     Decorator                          |
  * |--------------------------------------|           |---------------------------------------|      | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
  * |   Operation()                         |           |    Operation()  ○---------------|--→| Component-> Operation()  |
  * |_________________  ___|           |______________________|      |_____________________|
  *                                                                                      △                                            
  *                                                                                       |                                            
  *                                                     | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|                               
  *                      | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|           | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
  *                      |  ConcreateDecoratorA       |           | ConcreateDecoratorB         |
  *                      |--------------------------------------|           |---------------------------------------|      | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
  *                      |   Operation()                         |           |    Operation()     ○-------------|-→| Decorator:: Operation()      |
  *                      |   addedState                        |           |   AddedBehavior()                |      | AddedBehavior()                |
  *                      |_____________________|           |______________________|      |_________________ ___|
  *
角色:

      抽象构件(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
      具体构件(Concrete Component):定义一个将要接收附加责任的类。
      装饰(Decorator):持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口。
      具体装饰(Concrete Decorator):负责给构件对象“贴上”附加的责任。

装饰模式有两种实现模式,一是如上图所示采用委托的方式进行,二是采用子类化的方式进行,但从装饰的本意来讲还是采用委托的方式比较好。采用委托的方式可以动态,灵活的为对象增加新的责任和功能。

总结:

A)装饰模式并不改变构件原有的行为和特征,只是增加新的行为和特征,与适配器模式不同,装饰者只改变对象的责任,而非接口。而适配器模式让对象有一个全新的接口。

B) 虽然装饰模式可以视为组合模式只有一个组件的特例,但装饰者主要是为了附加责任而非对象聚合(aggregation)。
C)装饰模式和策略模式都可以让你改变对象,但装饰者模式只改变对象的外表,而策略模式是改变对象的内部。

D)采用子类化本身就可以增加新的特征和行为,但采用这种方式在需增加的特征和行为比较多样化的情况下,会使得类体系过于庞大,而装饰模式因为装饰和构件是组合方式进行,因此不仅灵活,而且也可以减少类的数量。而且不是所有情况下都可以采用子类化的方式进行(比如具体构件是密封类)

E)装饰模式比静态继承更灵活;而且可以避免在层次结构较高的类具有太多的特征;但缺点是会产生很多小对象(饰件);虽然Decorator从Component继承,但其本身与Component不是同一种对象,因此在命名上应特别注意,不要让用户产生误会。

F)装饰模式和桥模式都可以用来减少类(如果构件本身没有演化,或者演化很简单,则装饰模式并不能家少类,反而会增加类)的数量,都可以避免复杂的继承结构,。但也有如下区别:

1)在结构上两者有区别(比较图就知道)

2)实现方式上不同:装饰模式是通过将构件的核心功能和附加功能分离,类本身体系独自变化,而将附加性功能交给装饰子类,这样核心功能和附加功能各自独立变化,通过装饰子类对构件的封装来实现动态的为组建提供附加的功能。而桥模式则是将抽象行为的实现细节独立出来,构造一个实现化结构,通过抽象体系结结构和实现结构体系的组合达到适应变化的目的。

3)而且应用中,不同的装饰模式可以同时使用(比如对于对于图片,可以加边框,加滤境。而桥模式中的不同具体实现则不能同时应用。

4)装饰件是独立的,构件部分可以不使用饰件,而桥模式中实现部分只是相对独立,抽象部分必须依赖实现部分进行工作。

装饰模式也是包装模式的一种。

 

后记:虽然在装饰模式中我们不建议使用子类化方式来实现,但在实际应用中,有的时候我们还是需要用这种方式来实现,因为利用委托的方式来实现,装饰只能特定于某类构件,在我们需要装饰一些列类型的构件时,就无法实现。虽然采用子类化来实现大量增加装饰类,而且如果要重复装饰类的增加量就更大,但由于动态编译和动态中间语言指令注入的使用,这些子类可以动态生成,这就为所谓的AOP(面向方面编程)提供了一种可能。实际上Spring.Net 的AOP编程就是利用了装饰模式,而且是子类化。原因非常简单这种场景需要增加附加责任,但同时要求装饰必须与构件保持一致接口。Spring里面的AOP就是装饰模式+动态代码注入(动态编译或者利用EMIT)的利用,当然这种利用也进行了改良,通过结合观察者模式,将要附加的责任类作为观察者注入,这样,装饰类仅仅是按照一定的规则调用需要增加的责任类,大大减少了装饰类本身的数量,同时也增加了灵活性,不过这种情况下,装饰类本身的执行逻辑就变得复杂起来,特别是对于前置通知的处理,如果前置通知会影响是否真正执行具体任务类责任方法,在多个这样的前置通知下是一票否决制度,还是选票制度,就很难选择,而且如果具体责任类与通知类耦合很紧密的话,也不适合这种模式。Spring.net里的AOP注入虽然已经考虑得比较全面,但从可控性来讲,要完成这种横切目标最好的办法是在设计的时候就考虑到,而采用虚模式或其它方式来实现,不一定非得去使用AOP模式。一句话就是不要为了应用一种技术而应用一种技术。