乐趣区

装饰者模式

简介

装饰者模式可以动态地给一个对象添加行为,相对通过继承来扩展功能,它是一个灵活的选择。装饰者模式也使用了继承,只是为了统一接口,如果去除 CDecorator 和 CComponent 的继承关系,就有些像桥接模式了。主要区别是装饰者不需要动态的改变被装饰的对象,而桥接模式是多个维度独立的变化。

UML 类图

示例

陈奕迅有一首歌,last order,其中有句歌词,“麻烦你 加冰威士忌 对不起 来个 DOUBLE 的”。在这里我们假定威士忌是已经实现的类,不能再改动了。那就需要装饰者登场了。这里实现了加冰威士忌,也实现了来个 double 的。

装饰类,decorator.h

#include <iostream>
using namespace std;

class CWine
{
public:
    virtual string GetName() = 0;
    virtual double GetCost() = 0;};

class CWhisky:public CWine
{
public:
    string GetName()
    {return "Whisky";}
    double GetCost()
    {return 60.0;}
};

class CWineDecorator:public CWine
{
public:
    CWineDecorator(CWine* pWine):m_pWine(pWine){};
    string GetName()
    {return m_pWine->GetName();
    }
    double GetCost()
    {return m_pWine->GetCost();
    }
public:
    CWine* m_pWine;
};

class CIceDecorator:public CWineDecorator
{
public:
    CIceDecorator(CWine* pWine):CWineDecorator(pWine){}
    string GetName()
    {return m_pWine->GetName().append("+Ice");
    }
    double GetCost()
    {return m_pWine->GetCost() + 10;
    }
};

客户端调用,main.cpp

#include "decorator.h"

#define SAFE_DELETE(p) if(p){delete (p); (p) = NULL;}
int main(int argc, char* argv[])
{
    CWine* pWhisky = new CWhisky;
    CWine* pIceWhisky = new CIceDecorator(pWhisky);
    std::cout<<"Name:"<<pIceWhisky->GetName().c_str()<<endl;
    std::cout<<"Price:"<<pIceWhisky->GetCost()<<endl;

    CWine* pDoubleIceWhisky = new CIceDecorator(pIceWhisky);
    std::cout<<"Name:"<<pDoubleIceWhisky->GetName().c_str()<<endl;
    std::cout<<"Price:"<<pDoubleIceWhisky->GetCost()<<endl;

    SAFE_DELETE(pDoubleIceWhisky);
    SAFE_DELETE(pWhisky);
    SAFE_DELETE(pIceWhisky);
    return 0;
}

输出结果如下:

Name:Whisky+Ice
Price:70
Name:Whisky+Ice+Ice
Price:80
退出移动版