站点图标

设计模式 07 装饰模式

一、意图

    动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator比生成子类更加灵活。
    人话:我们希望对基类创建的部分对象添加某些功能,这时候使用装饰模式比创建多个子类更方便。

二、实际问题

    现在我们有一个基类产品:奶茶。现在我们有多种添加物:珍珠、椰果、布丁、红豆等。
    为了实现多种添加物的自由组合,我们现在又两种方式:(1)使用继承的方式,继承出多种不同的组合子类;(2)将添加物作为奶茶的成员,使用组合的方式完成。使用继承方式的缺点很明显:会有很多子类。使用组合方式来带的最大问题是:将会产生很长的构造函数参数。
    下面我们引入装饰模式。

三、UML

图1:装饰模式UML

四、实例

    下面我们来看一个实例:现在我们有一个产品——奶茶,以及两个添加物:珍珠和椰果。现在我们希望能自定义的为不同奶茶对象添加椰果和珍珠,同时我们希望能查看添加物以及添加后的总价格。
    我们选择一个抽象产品Imilktea作为基类,派生出具体产品类:Milktea、装饰类Decorator,同时装饰类派生出两个具体的装饰物:珍珠Bubble和椰果Coconut。

#include <iostream>

/* Visual Component */
class Imilktea
{
protected:
    int m_price;
public:
    Imilktea(const int& p_price = 10)
    {
        m_price = p_price;
    }

    virtual void show() const = 0;

    virtual int price() const = 0;
};

class Milktea : public Imilktea
{
public:
    Milktea(const int& p_price = 10) : Imilktea(p_price) {}

    void show() const override
    {
        std::cout << "Milktea" << std::endl;
    }

    int price() const override
    {
        return m_price;
    }
};

class Decorator : public Imilktea
{
protected:
    Imilktea* m_Component;
public:
    Decorator(Imilktea* p, const int& p_price) : Imilktea(p_price)
    {
        m_Component = p;
    }

    void show() const override
    {
        this->m_Component->show();
    }

    int price() const override
    {
        return this->m_Component->price();
    }
};

/* Concrete Decorator : 珍珠 */
class Bubble : public Decorator
{
private:
    int m_DecPrice;     // 添加物单价
public:
    Bubble(Imilktea* p, const int& p_DecPrice) : Decorator(p, p->price())
    {
        m_DecPrice = p_DecPrice;
    }

    void show() const override
    {
        std::cout << "Bubble" << std::endl;
        this->m_Component->show();
    }

    int price() const override
    {
        return m_DecPrice + this->m_Component->price();
    }
};

/* Concrete Decorator : 椰果 */
class Coconut : public Decorator
{
private:
private:
    int m_DecPrice;     // 添加物单价
public:
    Coconut(Imilktea* p, const int& p_DecPrice) : Decorator(p, p->price())
    {
        m_DecPrice = p_DecPrice;
    }

    void show() const override
    {
        std::cout << "Coconut" << std::endl;
        this->m_Component->show();
    }

    int price() const override
    {
        return m_DecPrice + this->m_Component->price();
    }
};

void Client(Imilktea* milktea)
{
    std::cout << "奶茶的成分:" << std::endl;
    milktea->show();
    std::cout << "奶茶的价格:" << milktea->price() << std::endl;

}

int main()
{
    /* 逐层装饰 */
    Imilktea* baseMilktea = new Milktea(10);    // 基本奶茶
    Imilktea* mtAddBubble = new Bubble(baseMilktea, 5);     // 加珍珠
    Client(mtAddBubble);
    Imilktea* mtAddBubbleAddCoconut = new Coconut(mtAddBubble, 3);  // 加珍珠、椰果
    Client(mtAddBubbleAddCoconut);
    Imilktea* mtAddDoubleBubble = new Bubble(mtAddBubble, 5);       // 加两分珍珠
    Client(mtAddDoubleBubble);

    delete baseMilktea, mtAddBubble, mtAddBubbleAddCoconut, mtAddDoubleBubble;
    return 0;
}
退出移动版