1. 程式人生 > >c++設計模式:裝飾者模式(Decorator Pattern)

c++設計模式:裝飾者模式(Decorator Pattern)

定義:

裝飾者模式動態的將責任附加到物件上。若要擴充套件功能,裝飾者提供了比繼承更有彈性的替代方案。

場景:

我們購買咖啡的時候,可以要求在其中加入各種調料,例如:蒸奶、豆漿、摩卡或覆蓋奶泡,而咖啡店也會根據所加入的調料收取不同的費用,所以當我們設計訂單系統的時候就需要考慮到這些調料部分啦。顧客的需求不一,如果我們針對每種配方都宣告一個類得話,系統的維護將會十分頭疼。此時裝飾者模式就派上用場啦。我們可以根據顧客的需要動態的擴充套件顧客定製的咖啡,讓其加上不同的調料,最終計算出顧客所需繳納的費用。它的實現有點類似於遞迴,在實際使用的時候可以慢慢體會。

類圖:

c++程式碼如下:

不使用指標版本:

複製程式碼
#include <iostream>
#include <string>
using namespace std;

class Beverage
{
public:
    virtual ~Beverage() {};
    virtual string getDescription(); // 必須是虛擬函式,否則會造成後期使用時描述顯示不正確    virtual double cost() = 0;
protected:
    string m_description;
};

class CondimentDecorator:public Beverage
{
public
: virtual string getDescription() = 0; }; class Espresso:public Beverage { public: Espresso(); double cost(); }; class HouseBlend:public Beverage { public: HouseBlend(); double cost(); }; class DarkRoast:public Beverage { public: DarkRoast(); double cost(); }; class Decaf:public
Beverage { public: Decaf(); double cost(); }; class Mocha:public CondimentDecorator { public: Mocha(Beverage* pBeverage); string getDescription(); double cost(); protected: Beverage* m_pBeverage; }; class Milk:public CondimentDecorator { public: Milk(Beverage* pBeverage); string getDescription(); double cost(); protected: Beverage* m_pBeverage; }; class Soy:public CondimentDecorator { public: Soy(Beverage* pBeverage); string getDescription(); double cost(); protected: Beverage* m_pBeverage; }; class Whip:public CondimentDecorator { public: Whip(Beverage* pBeverage); string getDescription(); double cost(); protected: Beverage* m_pBeverage; }; string Beverage::getDescription() { return m_description; } Espresso::Espresso() { m_description = "Espresso"; } double Espresso::cost() { return 1.99; } HouseBlend::HouseBlend() { m_description = "House Blend Coffee"; } double HouseBlend::cost() { return 0.89; } DarkRoast::DarkRoast() { m_description = "Dark Roast Coffee"; } double DarkRoast::cost() { return 0.99; } Decaf::Decaf() { m_description = "Decaf Coffee"; } double Decaf::cost() { return 1.05; } Mocha::Mocha(Beverage* pBeverage) { m_pBeverage = pBeverage; } string Mocha::getDescription() { return m_pBeverage->getDescription() + " + Mocha"; } double Mocha::cost() { return 0.20 + m_pBeverage->cost(); } Milk::Milk(Beverage* pBeverage) { m_pBeverage = pBeverage; } string Milk::getDescription() { return m_pBeverage->getDescription() + " + Milk"; } double Milk::cost() { return 0.10 + m_pBeverage->cost(); } Soy::Soy(Beverage* pBeverage) { m_pBeverage = pBeverage; } string Soy::getDescription() { return m_pBeverage->getDescription() + " + Soy"; } double Soy::cost() { return 0.15 + m_pBeverage->cost(); } Whip::Whip(Beverage* pBeverage) { m_pBeverage = pBeverage; } string Whip::getDescription() { return m_pBeverage->getDescription() + " + Whip"; } double Whip::cost() { return 0.10 + m_pBeverage->cost(); } int main() { Espresso espresso; cout << espresso.getDescription() << " $" << espresso.cost() << endl; DarkRoast darkRoast; Mocha mocha1(&darkRoast); Mocha mocha2(&mocha1); Whip whip1(&mocha2); cout << whip1.getDescription() << " $" << whip1.cost() << endl; HouseBlend houseBlend; Soy soy1(&houseBlend); Mocha mocha3(&soy1); Whip whip2(&mocha3); cout << whip2.getDescription() << " $" << whip2.cost() << endl; return 0; }
複製程式碼

使用指標版本:

複製程式碼
#include <iostream>
#include <string>
using namespace std;

class Beverage
{
public:
    virtual ~Beverage() {};
    virtual string getDescription();
    virtual double cost() = 0;
protected:
    string m_description;
};

class CondimentDecorator:public Beverage
{
public:
    virtual string getDescription() = 0;
};

class Espresso:public Beverage
{
public:
    Espresso();
    double cost();
};

class HouseBlend:public Beverage
{
public:
    HouseBlend();
    double cost();
};

class DarkRoast:public Beverage
{
public:
    DarkRoast();
    double cost();
};

class Decaf:public Beverage
{
public:
    Decaf();
    double cost();
};

class Mocha:public CondimentDecorator
{
public:
    Mocha(Beverage* pBeverage);
    ~Mocha();
    string getDescription();
    double cost();
protected:
    Beverage* m_pBeverage;
};

class Milk:public CondimentDecorator
{
public:
    Milk(Beverage* pBeverage);
    ~Milk();
    string getDescription();
    double cost();
protected:
    Beverage* m_pBeverage;
};

class Soy:public CondimentDecorator
{
public:
    Soy(Beverage* pBeverage);
    ~Soy();
    string getDescription();
    double cost();
protected:
    Beverage* m_pBeverage;
};

class Whip:public CondimentDecorator
{
public:
    Whip(Beverage* pBeverage);
    ~Whip();
    string getDescription();
    double cost();
protected:
    Beverage* m_pBeverage;
};

string Beverage::getDescription()
{
    return m_description;
}

Espresso::Espresso()
{
    m_description = "Espresso";
}

double Espresso::cost()
{
    return 1.99;
}

HouseBlend::HouseBlend()
{
    m_description = "House Blend Coffee";
}

double HouseBlend::cost()
{
    return 0.89;
}

DarkRoast::DarkRoast()
{
    m_description = "Dark Roast Coffee";
}

double DarkRoast::cost()
{
    return 0.99;
}

Decaf::Decaf()
{
    m_description = "Decaf Coffee";
}

double Decaf::cost()
{
    return 1.05;
}

Mocha::Mocha(Beverage* pBeverage)
{
    m_pBeverage = pBeverage;
}

Mocha::~Mocha()
{
    delete m_pBeverage;
}

string Mocha::getDescription()
{
    return m_pBeverage->getDescription() + " + Mocha";
}

double Mocha::cost()
{
    return 0.20 + m_pBeverage->cost();
}

Milk::Milk(Beverage* pBeverage)
{
    m_pBeverage = pBeverage;
}

Milk::~Milk()
{
    delete m_pBeverage;
}

string Milk::getDescription()
{
    return m_pBeverage->getDescription() + " + Milk";
}

double Milk::cost()
{
    return 0.10 + m_pBeverage->cost();
}

Soy::Soy(Beverage* pBeverage)
{
    m_pBeverage = pBeverage;
}

Soy::~Soy()
{
    delete m_pBeverage;
}

string Soy::getDescription()
{
    return m_pBeverage->getDescription() + " + Soy";
}

double Soy::cost()
{
    return 0.15 + m_pBeverage->cost();
}

Whip::Whip(Beverage* pBeverage)
{
    m_pBeverage = pBeverage;
}

Whip::~Whip()
{
    delete m_pBeverage;
}

string Whip::getDescription()
{
    return m_pBeverage->getDescription() + " + Whip";
}

double Whip::cost()
{
    return 0.10 + m_pBeverage->cost();
}
int main()
{
    Beverage* pBeverage = new Espresso();
    cout << pBeverage->getDescription() << " $" << pBeverage->cost() << endl;

    Beverage* pBeverage2 = new DarkRoast();
    pBeverage2 = new Mocha(pBeverage2);
    pBeverage2 = new Mocha(pBeverage2);
    pBeverage2 = new Whip(pBeverage2);
    cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() << endl;

    Beverage* pBeverage3 = new HouseBlend();
    pBeverage3 = new Soy(pBeverage3);
    pBeverage3 = new Mocha(pBeverage3);
    pBeverage3 = new Whip(pBeverage3);
    cout << pBeverage3->getDescription() << " $" << pBeverage3->cost() << endl;
    delete pBeverage;
    delete pBeverage2;
    delete pBeverage3;
    return 0;
}
複製程式碼

執行後結果如下:

Espresso $1.99
Dark Roast Coffee + Mocha + Mocha + Whip $1.49
House Blend Coffee + Soy + Mocha + Whip $1.34

參考圖書:《Head First 設計模式》