装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)
2017-04-25 11:11
525 查看
意图
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。对装饰和内容一视同仁。
Decorator是“进行Decorate(装饰)的主体”的意思。
适用性
当需要给一个类添加新的行为的时候,但基于开闭原则,就使用装饰模式。在以下情况使用Decorator模式:
1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
2. 处理那些可以撤销的职责
3. 当不能采用生成之类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或者类定义不能生成之类。
结构
参与者
Component
定义一个对象接口,可以给这些对象动态增加职责。ConcreteComponent
定义一个对象,可以给这个对象增加一些职责Decorator
维持一个指向Component对象的指针,并定义一个与Component接口一致的接口(可以直接实现Component接口)。ConcreteDecorator
向组件添加职责Client
使用组合完成功能的扩展。代码
Component
public interface Component { public void defaultMethod(); }
ConcreteComponent
public class ConcreteComponent implements Component{ public void defaultMethod(){ System.out.println("====ConcreteComponent===defaultMethod==="); } }
Decorator
public abstract class Decorator implements Component{ private Component component; public Decorator(Component component){ this.component = component; } public Component getComponent() { return component; } public void setComponent(Component component) { this.component = component; } }
ConcreteDecorator
public class ConcreteDecorator1 extends Decorator{ private int state = 0; public ConcreteDecorator1(Component component,int state) { super(component); this.state = state; } public void defaultMethod() { this.getComponent().defaultMethod(); } public void add1(){ System.out.println("====ConcreteDecorator1===add1==="+state); } public int getState() { return state; } public void setState(int state) { this.state = state; } } public class ConcreteDecorator2 extends Decorator{ public ConcreteDecorator2(Component component) { super(component); } public void defaultMethod() { this.getComponent().defaultMethod(); } public void add1(){ System.out.println("====ConcreteDecorator2===add1==="); } public void add2(){ System.out.println("====ConcreteDecorator2===add2==="); } }
Client
public class Client { public static void main(String[] args) { Component concreteComponent = new ConcreteComponent(); concreteComponent.defaultMethod(); System.out.println("========="); ConcreteDecorator1 concreteDecorator1 = new ConcreteDecorator1(concreteComponent,1); concreteDecorator1.defaultMethod(); concreteDecorator1.add1(); System.out.println("========="); ConcreteDecorator2 concreteDecorator2 = new ConcreteDecorator2(concreteComponent); concreteDecorator2.defaultMethod(); concreteDecorator2.add1(); concreteDecorator2.add2(); System.out.println("========="); ConcreteDecorator1 concreteDecorator3 = new ConcreteDecorator1(concreteDecorator2,1); concreteDecorator3.defaultMethod(); concreteDecorator3.add1(); System.out.println("========="); ConcreteDecorator2 concreteDecorator4 = new ConcreteDecorator2(concreteDecorator1); concreteDecorator4.defaultMethod(); concreteDecorator4.add1(); concreteDecorator4.add2(); } }
协作
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。效果
比静态集成更加灵活
与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加或删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以容易地重复添加一个特性。
避免在层次结构高层的类有太多的特征
Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征。相反,你可以定义一个简单的类,并且用Decorator类给他逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更容易不依赖于Decorator所扩展(甚至是不可预知的扩展)的类而独立定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴漏与添加的职责无关的细节。Decorator与它的Component不一样
Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此使用装饰时不应该依赖于对象标识。有许多小对象
采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是他们的类或是他们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。实现
使用Decorator模式时应该注意以下几点:接口一致性
装饰对象的接口必须和它所装饰的Component的接口是一致的,因此,所有的ConcreteDecorator类必须有一个公共的父类。省略抽象的Decorator类
当你仅需要添加一个职责时,没有必要定义抽象Decorator类。你尝尝需要处理现存的类层次结构而不是设计一个新系统,这时你可以把Decorator向Component转发请求的职责合并到ConcreteDecorator中。保持Component类的简单性
为了保证接口的一致性,组件和装饰必须有一个公共的Component父类。因此保持这个类的简单性是很重要的:即,它应集中于定义接口而不是存储数据。对数据表示的定义应该延迟到子类中,否则Component类会变得过于复杂和庞大,因而难以大量使用。赋予Component太多的功能也使得,具体的子类有一些它们并不需要的功能的可能性大大增加。改变对象外壳与改变对象内核
我们可以将Decorator看作一个对象的外壳,它可以改变这个对象的行为。另外一种方法是改变对象的内核(Strategy模式)。当Component类原本就很庞大时,使用Decorator模式代价太高,Strategy模式相对更好一些。在Strategy模式中,组件将它的一些行为转发给一个独立的策略对象,我们可以替换strategy对象,从而改变或扩充组件的功能。
由于Decorator模式仅从外部改变组件,因此组件无需对它的装饰有任何了解:也就是说这些装饰对组件是透明的。
在Strategy模式中,component组件本身知道可能进行哪些扩充,因此它必须引用并维护相应的策略。
基于Strategy的方法可能需要修改component组件以适应新的扩充。另一方面,一个策略可以有自己特定的接口,而装饰的接口则必须与组件的接口一致。这意味着即使Component类很庞大,策略也可以很小。
经典例子
相关模式
Adapter Pattern
Decorator模式不同于Adapter模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器讲给对象一个全新的接口。Decorator Pattern 不改变内容的接口(API)就能建立外框(穿透作用)。
Composite Pattern
可以将装饰视为一个退化的,仅有一个组件的组合。然而,装饰仅给对象添加一些额外的职责,它的目的不在于对象聚集。侧重通过递归组合构造类,使不同的对象、多重的对象可以“一视同仁”;而装饰模式仅仅是借递归组合来达到定义的目的
Strategy Pattern
用一个装饰你可以改变对象的外表;而Strategy模式使得你可以改变对象的内核。Decorator Pattern 可利用更换外框或增加其他外框的方式增加新功能;Strategy Pattern:以切换预算法则的方式变换功能。
敬请期待“组合模式(Composite Pattern,对象结构型模式)”
相关文章推荐
- 装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)
- 2.4 Decorator(装饰) -- 对象结构型模式
- (第Ⅲ部分 结构型模式篇) 第9章 装饰模式(Decorator Pattern)
- [导入]C#面向对象设计模式纵横谈(10):Decorator 装饰模式(结构型模式).zip(9.84 MB)
- C#设计模式之八装饰模式(Decorator Pattern)【结构型】
- 面向对象设计模式之Decorator装饰模式(结构型)
- (第Ⅲ部分 结构型模式篇) 第9章 装饰模式(Decorator Pattern)
- Decorator(装饰、油漆工)--对象结构型模式
- (第Ⅲ部分 结构型模式篇) 第9章 装饰模式(Decorator Pattern)
- 七个结构型模式4:装饰模式-Decorator Pattern【学习难度:★★★☆☆,使用频率:★★★☆☆】
- 设计模式十:decorator(装饰)——对象结构型模式
- 装饰模式(Decorator/Wrapper Pattern)
- 设计模式之十四:Decorator(装饰)—对象结构型模式
- C#面向对象设计模式第十讲:Decorator 装饰模式(结构型模式)
- "围观"设计模式(13)--结构型之装饰模式(Decorator Pattern)
- 结构型模式之装饰模式(Decorator Pattern)C++实现
- Decorator(装饰)-对象结构型模式
- 我读设计模式之装饰模式(Decorator Pattern)
- 第十九章 装饰模式(Decorator Pattern)
- .NET设计模式(10):装饰模式(Decorator Pattern)