【转】设计模式学习笔记(9)-装饰

装饰(Decorator)模式和Adapter、Composite模式有点像,但目的则不同。现在我们看来如果为一个类增加职责,有两种方案,继承和组合。让子类继承父类并扩展父类的功能。但是这种方式有很大缺陷,它是静态的,即在编译时就决定的;另外如果有大量不同的对象,用这种方法会产生子类爆炸,不利于系统的编写与维护。今天要讲的装饰模式就是为了解决这个问题的,它的意图就是:动态地给一个对象添加一些额外的职责

考虑这样一个例子,我们有一张信纸(Paper),这张纸是空白的,如果要是N张信纸需要装订起来,如果信纸都一样那比较好办,直接new N个paper对象。然而市场上有一种很花哨的笔记本,每张页面都不一样,有很多装饰性的图案。这时直接new 就不行了,如果用子类呢?每一页都是一个子类,貌似开销太大,而且也不够灵活。我们想一下整整工厂里是怎样制作的。工厂里先制作一个基本的Paper,类似于毛坯房,然后交给各个处理机器将装饰性图案印上去。我们的软件设计能不能这样做呢?这就是装饰模式。我们来详细设计一下:

有一个Paper抽象类,它有两个子类:BasicPaper和Decorator,分别表示基本纸张和装饰元素。然后Decorator有几个简单的实现类:

Decorator中的draw方法直接调用component的draw方法

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Paper
{
public:
    virtual string draw() = 0;
};
class BasicPaper : public Paper
{
public:
    string draw()
    {
        return "This is a basic paper";
    }
};
 
class Decorator : public Paper
{
private:
    Paper* _paper;
public:
    Decorator(Paper* paper) : _paper(paper) {}
    string draw()
    {
        return _paper->draw();
    }
};
class LineDecorator : public Decorator
{
public:
    LineDecorator(Paper* paper) : Decorator(paper) {}
    string draw()
    {
        return Decorator::draw() + ", with linedecorator";
    }
};
class BorderDecorator : public Decorator
{
public:
    BorderDecorator(Paper* paper) : Decorator(paper) {}
    string draw()
    {
        return Decorator::draw() + ", with borderdecorator";
    }
};

在上面的代码中Paper中有个draw方法,它返回一个字符串,而子类Decorator都返回with xxx的字符串。
主方法里这样写:

1
2
Paper* paper = new LineDecorator(new BorderDecorator(new BasicPaper));
cout << paper->draw() << endl;

 

是不是很奇特?再new的时候我们层层嵌套,这样就保证了paper是一个拥有多项职责的的对象。而且这个对象是独一无二的,是运行时生成的。输出的结果如下:

1
This is a basic paper, with borderdecorator, with linedecorator

结果是很完美的,最终的字符串整合符合我们的要求。
如果我们要加两层linedecorator呢?也很简单,改成:

1
Paper* paper = new LineDecorator(new LineDecorator(new BorderDecorator(new BasicPaper)));

 

从上面的例子中可以看出Decorator模式非常灵活,类似于组合模式,它也是动态生成对象,并且逐步为对象添加职责,甚至是无限的职责。

使用Decorator模式有最重要的一点:保持接口的一致性,上面的例子中所有的类都继承于Paper,这样就保持则使用这些对象的统一性,对客户来说这些都是透明的。

最后来看一下Decorator模式的适用性:

  • 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责
  • 处理那些可以撤销的职责
  • 当不能采用生成子类的方法进行扩充时

Decorator模式的使用范围主要体现在图形界面设计和数据流。在GUI设计中,可以为一个界面元素添加不同的标识,而在流中为了统一流的操作接口往往也是用Decorator,这点在Java程序设计中十分常见。

转自:http://lecoding.com/articles/196.html

posted on 2013-03-05 14:51  TheKingOfKingFish  阅读(117)  评论(0)    收藏  举报

导航