C++實現(xiàn)設(shè)計模式之裝飾者模式詳解
設(shè)計模式和設(shè)計原則
裝飾者模式動態(tài)地將責(zé)任附加到對象上。若要擴(kuò)展功能,裝飾者模式提供了比繼承更有彈性的替代方案。
裝飾者模式遵循的設(shè)計原則:
類應(yīng)該對擴(kuò)展開放,對修改關(guān)閉。
裝飾者模式中的類
裝飾者模式中的類如下圖,C++設(shè)計模式之裝飾模式

其中Component抽象組件類,即被裝飾的類,每個組件都可以單獨(dú)使用,或者被裝飾者包起來使用。該類中聲明了一些接口,這些接口將在具體組件,以及具體裝飾者中實現(xiàn)。
ConcreteComponent具體組件類,繼承自組件類,是我們要動態(tài)地加上新行為(即要裝飾)的對象。
Decorator抽象裝飾者類是具體裝飾者的基類,裝飾者類中包含一個組件類型的指針,是為了記錄被裝飾的對象。當(dāng)需要獲得裝飾之后的行為時可以通過該指針獲得被裝飾者的行為加上裝飾者自身的行為,這個在下面案例中會看到。
ConcreteDecorator具體裝飾者類,裝飾者類要實現(xiàn)Decorator中定義的方法,另外可以加一些新的方法。
如上圖所示裝飾者和被裝飾者必須是一樣地類型,也就是有共同地超類,這是相當(dāng)關(guān)鍵的地方。這是因為裝飾者必須能取代被裝飾者。
案列描述
咖啡館提供各種各樣的咖啡,每種咖啡可以加不同調(diào)料(摩卡、奶泡,雙糖,半糖等)。以飲料為抽象組件,各種各樣的咖啡為具體組件,咖啡中的不同調(diào)料為裝飾者。每種咖啡以及調(diào)料有各自的描述和價格,使用裝飾者模式,加了不同調(diào)料的咖啡也可以輕松給出描述和價格。
下面例子中生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.。
代碼實現(xiàn)
聲明:類的聲明和實現(xiàn)在同一個文件里是個壞習(xí)慣,壞習(xí)慣,壞習(xí)慣,但因為我懶,還是寫一起了,大家不要效仿,要引以為戒,要引以為戒,要引以為戒。
首先定義抽象組件類Beverage和抽象裝飾者類CondimentDecorator,代碼如下。這里關(guān)鍵的地方是抽象裝飾者繼承自抽象組件,且包含一個抽象組件的引用。
//抽象組件類-飲料
class Beverage
{
public:
Beverage() :m_description("Unknown Beverage")
{
}
virtual std::string getDescription(){ return m_description; }
virtual double cost() = 0;
protected:
std::string m_description;
};
//抽象裝飾者類-調(diào)料,繼承自飲料類
class CondimentDecorator :public Beverage
{
public:
CondimentDecorator(Beverage* berverge)
:m_beverage(berverge)
{
}
virtual std::string getDescription() = 0;//定義成純虛函數(shù),是為了強(qiáng)制子類實例化時必須實現(xiàn)它。
protected:
Beverage* m_beverage;
};
然后定義具體組件,即三種具體的咖啡DarkRoast、Espresso和HouseBlend。
//三個具體組件
class DarkRoast :public Beverage
{
public:
DarkRoast()
{
m_description = "DarkRoast";
}
double cost()
{
return 2.99;
}
};
class Espresso :public Beverage
{
public:
Espresso()
{
m_description = "Espresso";
}
double cost()
{
return 1.99;
}
};
class HouseBlend :public Beverage
{
public:
HouseBlend()
{
m_description = "HouseBlend";
}
double cost()
{
return 0.89;
}
};
再定義兩個具體裝飾者類,即兩種調(diào)料Mocha和Milk。
//兩個具體裝飾者
class Mocha :public CondimentDecorator
{
public:
Mocha(Beverage* beverage) :CondimentDecorator(beverage)
{
}
std::string getDescription()
{
return m_beverage->getDescription() + " Mocha";
}
double cost()
{
return 0.2 + m_beverage->cost();
}
};
class Milk :public CondimentDecorator
{
public:
Milk(Beverage* beverage) :CondimentDecorator(beverage)
{
}
std::string getDescription()
{
return m_beverage->getDescription() + " Milk";
}
double cost()
{
return 0.5 + m_beverage->cost();
}
};
最后在main函數(shù)中寫測試代碼,生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.
//測試代碼
int main()
{
//不加調(diào)料的Espresso
Beverage* beverage = new Espresso();
std::cout << beverage->getDescription() << " ¥" << beverage->cost() << std::endl;
//加雙倍摩卡和奶泡的DarkRoast
Beverage* beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Milk(beverage2);
std::cout << beverage2->getDescription() << " ¥" << beverage2->cost() << std::endl;
//加雙倍奶泡的和一份摩卡的HouseBlend
Beverage* beverage3 = new HouseBlend();
beverage3 = new Mocha(beverage3);
beverage3 = new Milk(beverage3);
beverage3 = new Milk(beverage3);
std::cout << beverage3->getDescription() << " ¥" << beverage3->cost() << std::endl;
system("pause");
delete beverage;
delete beverage2;
delete beverage3;
}
運(yùn)行結(jié)果

總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語言數(shù)據(jù)類型枚舉enum全面詳解示例教程
生活中有很多地方會用到枚舉,比如一周有7天,可以一一枚舉;性別有男、女...等等都可以可以一一枚舉,今天來和筆者一起學(xué)習(xí)一下c語言枚舉吧2021-10-10
C/C++ Qt 數(shù)據(jù)庫與Chart歷史數(shù)據(jù)展示
這篇文章主要介紹了Qt利用Qchart組件展示數(shù)據(jù)庫中的歷史數(shù)據(jù)。文中的示例代碼講解清晰,具有一定的學(xué)習(xí)和工作價值,感興趣的小伙伴可以學(xué)習(xí)一下2021-12-12

