现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

重学设计模式 – Decorator模式

2012-07-19 18:03 工业·编程 ⁄ 共 1630字 ⁄ 字号 暂无评论

1、 Decorator模式简介

《设计模式》一书中对Decorator模式的意图是这样叙述的:

动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式比生成子类更为灵活。

Decorator模式的工作原理是:可以创建始于Decorator对象(负责新功能的对象)终于原对象的一个对象“链”。实现方法:将原对象作为新对象的成员。

clip_image001

如上图中Decorator模式的类图隐含了一条对象链。每条链都始于一个Component对象(ConcreteComponent或Decorator)。每个Decorator对象后面都跟着另一个Decorator对象或原ConcreteComponent对象。对象链总是终于一个ConcreteComponent对象。

例如,在上图中,ConcreteDecoratorB对象执行其Operation方法,然后调用Decorator类的Operation方法。这又将调用ConcreteDecoratorB对象之后的Component对象的Operation方法。

clip_image002

上图为设置表头和页脚的Decorator模式类图,如果需要这样的一张票据:

Header1

Header2

Sales Ticket

Footer1

则实现代码:

Component * pComponent = new Header1(newHeader2(new Foorer1(new SalesTicket())));

pComponent->prtTicket();

2、 Decorator模式关键特征

意图

动态地给一个对象添加职责

问题

要使用的对象将执行所需基本功能。但是,可能需要为这个对象将添加某些功能,这些附加功能可能发生在对象的基础功能之前或之后。

解决方案

可以无需创建子类,而扩展一个对象的功能

参与者与协作者

ConcreteComponent让Decorator对象为自己添加功能。有时候用ConcreteComponent的派生类提供核心功能,在这种情况下ConcreteComponent类就不再是具体的,而是抽象的。Component类定义了所有这些类所使用的接口。

效果

所添加的功能放在小对象中。好处是可以在ConcreteComponent对象功能之前或之后动态添加功能。注意,虽然装饰对象可以在被装饰对象之前或之后添加功能,但对象链总是终于ConcreteComponent对象。

实现

创建一个抽象类来表示原类和要添加到这个类的功能。在装饰类中,将对新功能的调用放在对紧随其后对象的调用之前或之后,以获得正确的顺序。

3、 Decorator模式的本质

Decorator模式的使用场合是:各种可选功能在另一个肯定要执行的功能之前或之后执行。

上述Decorator模式的实现实际上是一种很糟糕的设计。例如,假设这些“装饰对象”(即可选功能)是由不同的开发组开发的,而且系统可能抛出一些异常,需要由每个装饰对象进行处理。理想情况下,可以相信这些开发组都能够按预期地实现—正确地捕获这些异常。然而,如果他们没有做到会怎么样呢?如果一个异常抛出了,而某个开发组编写的代码无法捕获它,整个系统这时可能crash。

另一种方案是让客户对象捕获异常。但是,这也就丧失了Decorator模式的价值,因为客户类需要完成比它以前更多的任务。

更健全的解决方案是实现一个与ConcreteComponent对象接口相同的对象集合。它调用装饰对象,捕获后者没有捕获的任何必须捕获的异常。事实上,这可能具有附加的好处:装饰对象再也不必要与ConcreteComponent对象接口相同了。

关键在于,Decorator模式有如下约束因素:

  • 存在几种可选功能;
  • 这些装饰对像可能遵循也可能不遵循所有规则;
  • 需要某种方式以所需的不同顺序调用这些装饰对象,但是又不能加重客户对象的负担;
  • 不希望应用程序必须承担知道使用哪些装饰对象(甚或是否存在)的职责。

这样思考Decorator模式将使模式的意图和实现分离开来。

给我留言

留言无头像?