天天看点

【设计模式学习笔记十】【结构型模式】【装饰模式(Decorator)】

本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.csdn.net/lovelion/article/details/17517213

主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。

我应该理解和掌握的:

1)能够画出这个设计模式的架构框图;

2)能够根据架构框图写出对应的伪代码;

3)这个模式的应用场景,主要优缺点。

1.装饰模式

装饰模式在不改变对象本身功能的基础上添加额外的功能,比如给照片添加一个相框。同时他也是一种替代继承的技术,使用关联取代继承;在装饰模式中引入装饰类,在装饰类中既可以调用待装饰的原有类方法,还可以新增方法,以扩充原有功能。

(1)定义

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

1) 装饰模式结构图

【设计模式学习笔记十】【结构型模式】【装饰模式(Decorator)】

2)参与者

a) Component(抽象构件):定义一个对象业务方法,是具体构建和抽象装饰类的共同父类,客户端针对它编程。

b) ConcreteComponent(具体构件):定义具体构件,实现父类业务方法,装饰类将会给这个对象增加额外的职责。

c) Decorator(抽象装饰类):抽象构件子类,用于关联一个抽象构件的指针,并定义一个与Component一致的接口,直接调用装饰之前对象的业务方法。

d) ConcreteDecorator(具体装饰类):向具体构件增加额外的职责,不同的具体装饰类增加不同的职责。调用抽象装饰类的operation方法,同时增加新的业务方法,这边是装饰额外的功能。

3) 看图写代码

/*
 ** FileName     : DecoratorPattern
 ** Author       : lin005
 ** Date         : 2015/01/27
 ** Description  : More information, please go to http://blog.csdn.net/amd123456789
 */
class Component
{
public:
    virtual void operation() = 0;
};
//具体构建类
class ConcreteComponent:public Component
{
public:
    void operation()
    {
        cout<<"ConcreteComponent"<<endl;
    }
};
//抽象装饰类
class Decorator:public Component
{
public:
    //注入抽象类,保持一个对component的引用
    Decorator(Component* c)
    {
        _component = c;
    }
    virtual void operation()//直接调用component的方法
    {
        _component->operation();
    }
    ~Decorator()
    {
        if(_component != NULL)
        {
            delete _component;
            _component = NULL;
        }
    }
protected:
    //关联一个component
    Component* _component;
};
//具体状态装饰类
class ComcreteDecoratorA:public Decorator
{
public:
    //注入一个component对象
    ComcreteDecoratorA(Component* c):Decorator(c){}
    //对客户透明,始终还是调用operation()
    virtual void operation()
    {
        //增加state状态
        addstate();
        Decorator::operation();
    }
    //装饰类要添加的职能
    void addstate()
    {
        cout<<"要装饰的状态方法"<<endl;
    }
};
//具体行为装饰类
class ComcreteDecoratorB:public Decorator
{
public:
    //注入一个component对象
    ComcreteDecoratorB(Component* c):Decorator(c){}
    virtual void operation()
    {
        //装饰行为职能
        addbehavior();
        Decorator::operation();
    }
    void addbehavior()
    {
        cout<<"要装饰的行为方法"<<endl;
    }
};
//客户端测试
int main(int argc, const char * argv[]) {
    //客户端针对抽象编程
    Component *c;
    Component* dA;
    Component* dB;
    Component* dAB;
    
    c = new ConcreteComponent();//具体构件对象,即要装饰前的对象
    dA = new ComcreteDecoratorA(c);//具体装饰对象A
    dB = new ComcreteDecoratorB(c);//具体装饰对象B
    dAB = new ComcreteDecoratorA(dB);//同时装饰A和B,非常方便,直接嵌套

    c->operation();
    dA->operation();
    dB->operation();
    dAB->operation();
    
    return 0;
}
           

(2)总结

1)优点:

a) 对于扩展一个对象的功能,装饰模式比静态继承更灵活,也很容易重复添加一个特性,不会导致类的个数急剧增加。

b) 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,得到功能更为强大的对象。

c) 符合开闭,具体构件类和具体装饰类可以独立变化,按需增加新的具体构件类和具体装饰类。

2)缺点

a) 会产生许多小对象;这些对象仅仅在他们相互连接的方式上有所不同,而不是他们的类或是他们的属性值有所不同。

b) 对于了解这些系统的人来说,很容易对他们进行定制,但是很难学习这些系统,排错也困难。

3) 注意事项

a) 接口一致性。装饰对象的接口必须与他所装饰的component的接口是一致的。

b) 保持Component类的简单性。它应集中于定义接口而不是存储数据,对于数据的表示应延迟到子类,否则Component会变得过于复杂的庞大,难以大量使用。我们应该通过装饰类对其进行扩展。

c) 可以省略抽象的Decorator类,当你仅需要添加一个职责时,没必要定义抽象Decotator类。你常常需要处理现存的类层次结构而不是设计一个新的系统,这时可以把Decorator向Component转发请求的职责合并到ComcreteDecorator中。

d) 如果只有一个具体构件类,那么抽象装饰类可以作为该具体构件结构类的直接子类。如下图:

【设计模式学习笔记十】【结构型模式】【装饰模式(Decorator)】

(3)适用场景

1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2)处理那些可以撤销的职责,按需再进行添加。同时装饰者模式的行为具有可叠加性。

3)当不能采用生成子类的方法进行扩充。一种是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种是可能因为类定义被隐藏,或类定义不能生成子类。

继续阅读