1. 程式人生 > >C++設計模式--裝飾者模式

C++設計模式--裝飾者模式

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

                                                                                                                                             --《Head First 設計模式》

裝飾者模式簡單來說就是對已有的類進行拓展但有不要求修改已有的類的程式碼,也就是符合了“對擴充套件開放,對修改關閉”的設計原則。

裝飾者模式的優缺點:

優點

           1、裝飾者模式可以提供比繼承更多的靈活性

           2、可以通過一種動態的方式來擴充套件一個物件的功能,在執行時選擇不同的裝飾器,從而實現不同的行為。

           3、通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。可以使用多個具體裝飾類來裝飾同一物件,得到功能更為強大的物件。

           4、具體構件類與具體裝飾類可以獨立變化,使用者可以根據需要增加新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有程式碼無須改變,符合“開閉原則”。

缺點

           1、會產生很多的小物件,增加了系統的複雜性

           2、這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承更加易於出錯,排錯也很困難,對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為煩瑣。

裝飾者模式的使用場景

  1、在不影響其他物件的情況下,以動態、透明的方式給單個物件新增職責。

  2、需要動態地給一個物件增加功能,這些功能也可以動態地被撤銷。  當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴充套件和維護時。

(以上內容來源於網路)

C++實現裝飾者模式:

場景:原有飲料類,咖啡類繼承了飲料了。現在需要新增調料類,為咖啡新增調料,要求不能修改原有的類。

#ifndef __BEVERAGE_H__
#define __BEVERAGE_H__

#include <string>
/*
 * 飲料類
*/
class Beverage
{
public:
    virtual std::string getDescription() const
    {
        return description;
    }

    virtual double cost() = 0;

public:
    std::string description = "Unknow Beverage";
};
#endif
#ifndef __COFFEE_H__
#define __COFFEE_H__

//咖啡類
#include "beverage.h"

//濃咖啡
class Espresso : public Beverage
{

public:
    Espresso();
    ~Espresso();
    virtual std::string getDescription() const override;
    virtual double cost() override;
};


//黑咖啡
class HouseBlend : public Beverage
{
public:
    HouseBlend();
    ~HouseBlend();
    virtual std::string getDescription() const override;
    virtual double cost() override;
};
#endif
//咖啡實現類
#include "coffee.h"

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

Espresso::~Espresso()
{
}

std::string Espresso::getDescription() const
{
    return description;
}

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

HouseBlend::HouseBlend()
{
    description = "HouseBlend";
}

HouseBlend::~HouseBlend()
{
}

std::string HouseBlend::getDescription() const
{
    return description;
}

double HouseBlend::cost()
{
    return .89;
}

以下是調味料的實現:

#ifndef __CONDIMENTDECORATOR_H__
#define __CONDIMENTDECORATOR_H__

#include <string>

#include "beverage.h"

//調料裝飾類
class CondimentDecorator : public Beverage
{
public:
    virtual std::string getDescription() const override = 0;
    virtual double cost() override = 0;
};

//調料--摩卡
class Mocha : public CondimentDecorator
{
public:
    explicit Mocha(Beverage* beverage);
    ~Mocha();
    virtual std::string getDescription() const override;
    virtual double cost() override;

private:
    Beverage* m_beverage;
};

//調料--牛奶
class Milk : public CondimentDecorator
{
public:
    explicit Milk(Beverage* beverage);
    ~Milk();
    virtual std::string getDescription() const override;
    virtual double cost() override;

private:
    Beverage* m_beverage;

};

#endif
#include "condimentdecorator.h"

Mocha::Mocha(Beverage* beverage):m_beverage(beverage)
{

}

Mocha::~Mocha()
{

}

std::string Mocha::getDescription() const
{
    return m_beverage->getDescription() + ",Mocha";
}

double Mocha::cost()
{
    return m_beverage->cost() + .20;
}

Milk::Milk(Beverage* beverage):m_beverage(beverage)
{

}

Milk::~Milk()
{

}

std::string Milk::getDescription() const
{
    return m_beverage->getDescription() + ",Milk";
}

double Milk::cost()
{
    return m_beverage->cost() + .50;
}

生產咖啡並新增調料:

#include <iostream>

#include "beverage.h"
#include "coffee.h"
#include "condimentdecorator.h"

using namespace std;
int main()
{
    Beverage* beverage = new Espresso(); 
    Beverage* beverage2 = new HouseBlend();
    cout << beverage->getDescription() << " and cost = " 
         << beverage->cost() << endl;

    cout << beverage2->getDescription() << " and cost = "
             << beverage2->cost() << endl;
    
    //為HouseBlend的咖啡加上摩卡
    beverage2 = new Mocha(beverage2);
    cout << beverage2->getDescription() << " and cost = "
             << beverage2->cost() << endl;
    
    //再為加了摩卡的HouseBlend咖啡加上牛奶
    beverage2 = new Milk(beverage2);
    cout << beverage2->getDescription() << " and cost = "
             << beverage2->cost() << endl;

    delete beverage;
    delete beverage2;
    return 0;
}

Linux下編譯:

g++ -std=c++11 -o main main.cc coffee.cc condimentdecorator.cc
./main

結果是:

Espresso and cost = 1.99                //沒有加調料的濃咖啡
HouseBlend and cost = 0.89              //沒有加調料的黑咖啡
HouseBlend,Mocha and cost = 1.09        //加了摩卡的黑咖啡
HouseBlend,Mocha,Milk and cost = 1.59   //加了摩卡和牛奶的黑咖啡