C++设计模式 装饰器模式
文章目錄
- 1. 先驗(yàn)知識(shí)
- 2. 裝飾器模式相關(guān)概念
- 3. 裝飾器模式的應(yīng)用
- 3.1 應(yīng)用1: 給形狀添加新的特征 不同形狀加紅
- 3.2 應(yīng)用2: 給一個(gè)人穿不同的衣服
- a 直接person類, 增加穿不同衣服的方法
- b. 把person類拆解, 里面的衣服分別寫成類的形式
- 核心關(guān)鍵最終的代碼和邏輯
- c 裝飾器模式下的穿衣系統(tǒng)設(shè)計(jì)
學(xué)習(xí)設(shè)計(jì)模式的主要目的是為了學(xué)習(xí)整個(gè)軟件開發(fā)的思維邏輯, 這是上百年程序員大佬們總結(jié)出來(lái)的精華, 就像學(xué)好數(shù)理化走遍天下都不怕是一個(gè)邏輯, 我永遠(yuǎn)相信, 業(yè)務(wù)開發(fā)跟設(shè)計(jì)模式息息相關(guān), 個(gè)人思維邏輯與算法息息相關(guān), 活到老, 學(xué)到老, 與君共勉即努力.
- 平臺(tái) win10子系統(tǒng) Ubuntu18.04
- 編譯器 gcc dbg
- 編輯器 VScode
1. 先驗(yàn)知識(shí)
- 子類繼承父類初始化父類: 子類構(gòu)造函數(shù)(參數(shù)) : 父類構(gòu)造函數(shù)(父類構(gòu)造函數(shù)參數(shù)){}
- 子類使用父類中的成員: 父類名::父類成員
2. 裝飾器模式相關(guān)概念
裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。
這種模式創(chuàng)建了一個(gè)裝飾類,用來(lái)包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。
按照人話講: 就是先實(shí)例化一個(gè)對(duì)象, 在給這個(gè)對(duì)象增加新的功能, 比繼承更加靈活的操作, 給一個(gè)new出來(lái)的對(duì)象披上一層外衣
意圖: 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),裝飾器模式相比生成子類更為靈活。
主要解決:一般的,我們?yōu)榱藬U(kuò)展一個(gè)類經(jīng)常使用繼承方式實(shí)現(xiàn),由于繼承為類引入靜態(tài)特征,并且隨著擴(kuò)展功能的增多,子類會(huì)很膨脹。
何時(shí)使用:在不想增加很多子類的情況下擴(kuò)展類。
如何解決:將具體功能職責(zé)劃分,同時(shí)繼承裝飾者模式。
關(guān)鍵代碼: 1、Component 類充當(dāng)抽象角色,不應(yīng)該具體實(shí)現(xiàn)。 2、修飾類引用和繼承 Component 類,具體擴(kuò)展類重寫父類方法。
應(yīng)用實(shí)例: 1、孫悟空有 72 變,當(dāng)他變成"廟宇"后,他的根本還是一只猴子,但是他又有了廟宇的功能。 2、不論一幅畫有沒有畫框都可以掛在墻上,但是通常都是有畫框的,并且實(shí)際上是畫框被掛在墻上。在掛在墻上之前,畫可以被蒙上玻璃,裝到框子里;這時(shí)畫、玻璃和畫框形成了一個(gè)物體。
優(yōu)點(diǎn):裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能。
缺點(diǎn):多層裝飾比較復(fù)雜。
使用場(chǎng)景: 1、擴(kuò)展一個(gè)類的功能。 2、動(dòng)態(tài)增加功能,動(dòng)態(tài)撤銷。
注意事項(xiàng):可代替繼承。
3. 裝飾器模式的應(yīng)用
3.1 應(yīng)用1: 給形狀添加新的特征 不同形狀加紅
創(chuàng)建形狀, 擁有方形和圓形, 又想要給方形和圓形染色為紅色, 按照以往的邏輯, 需要給方形和圓形在增加對(duì)應(yīng)的子類, 在子類里面增加紅色, 但是在這里, 我們嘗試換一種思路, 增加一個(gè)形狀子類命名為抽象裝飾器類, 里面創(chuàng)建對(duì)應(yīng)的形狀對(duì)象, 這樣當(dāng)傳入的不管是圓還是方形, 都在這個(gè)類里面增加染為紅色的方法, 這樣就實(shí)現(xiàn)了裝飾器的功能
#include <iostream> #include <algorithm> using namespace std;// 創(chuàng)建形狀抽象類 class Shape{ public:virtual void draw() = 0; };// 創(chuàng)建圓類 class Rectangle : public Shape{ public:void draw(){cout << "create Rectangle ... " <<endl;} };// 創(chuàng)建方類 class Circle : public Shape{ public:void draw(){cout << "create Circle ... " <<endl;} };// 創(chuàng)建修飾器的抽象類, 里面先包含一個(gè)形狀, 然后給這個(gè)形狀后面再添加功能 class ShapeDecorator : public Shape{ protected:Shape *decoratedShape = nullptr; // 創(chuàng)建一個(gè)基礎(chǔ)形狀, 并在修飾器初始化時(shí)初始化這個(gè)形狀public:ShapeDecorator(Shape *decoratedShape): decoratedShape(decoratedShape){}virtual void draw()=0; };// 創(chuàng)建擴(kuò)展了ShapeDecorator類的實(shí)體裝飾類 將形狀顏色變?yōu)榧t色 class RedShapeDecorator : public ShapeDecorator{ public:// 顯示的初始化父類的成員變量 RedShapeDecorator(Shape *decoratedShape) : ShapeDecorator(decoratedShape){} void draw(){ShapeDecorator::decoratedShape->draw(); // 顯式使用父類成員變量, 好像沒啥用 setRedBorder(ShapeDecorator::decoratedShape); // 然后給在調(diào)用增加功能也就是red顏色}private:void setRedBorder(Shape *decoratedShape){cout << "border color : rrred" <<endl;} }; int main(int argc, char const *argv[]) {Shape *circle = new Circle(); // 形狀創(chuàng)建一個(gè)圓, 多態(tài)ShapeDecorator *redCircle = new RedShapeDecorator(new Circle()); // 創(chuàng)建一個(gè)紅圓ShapeDecorator *redRectangle = new RedShapeDecorator(new Rectangle()); // 創(chuàng)建一個(gè)紅正方// Shape *redCircle = new RedShapeDecorator(new Circle());// Shape *redRectangle = new RedShapeDecorator(new Rectangle());cout << "實(shí)驗(yàn)一: 創(chuàng)建一個(gè)普通的圓, 并打印" << endl;circle->draw();cout << "實(shí)驗(yàn)二: 創(chuàng)建一個(gè)帶有紅邊的圓" <<endl;redCircle->draw();cout << "實(shí)驗(yàn)二: 創(chuàng)建一個(gè)帶有紅邊的方" <<endl;redRectangle->draw();delete circle;delete redCircle;delete redRectangle; }- 結(jié)果
3.2 應(yīng)用2: 給一個(gè)人穿不同的衣服
要求: 給人搭配不同服飾的系統(tǒng), 比如QQ秀, QQ飛車這種
比如給人穿T恤和大褲衩
接下來(lái)通過(guò)不同的思路實(shí)現(xiàn), 直到找到最優(yōu)解決方案
a 直接person類, 增加穿不同衣服的方法
但是如果需求中增加 “超人裝飾”?
解決方案: 改一下Persion類即可, 但是這樣違背了開放-封閉原則
b. 把person類拆解, 里面的衣服分別寫成類的形式
這樣做, 如果需要超人就增加個(gè)超人的子類即可
新的問(wèn)題: 形象展示過(guò)程中, 每穿一件衣服, 就需要形象展示, 有一種眾目睽睽之下脫衣服的意思, 所以能不能通過(guò)內(nèi)部組裝完畢再顯示, (這里涉及到建造模式), 但是非也, 因?yàn)榻ㄔ爝^(guò)程是不穩(wěn)定的, 這里可能是先穿西裝, 再穿T恤等, 通俗來(lái)講, 通過(guò)服飾組合, 展現(xiàn)一個(gè)有個(gè)性的人有無(wú)數(shù)種方案, 并非是固定的
因此: 我們需要把所有需要的功能按照正確的順序串聯(lián)起來(lái)進(jìn)行控制
核心關(guān)鍵最終的代碼和邏輯
首先給出裝飾器模式的邏輯代碼, 也可以運(yùn)行成功
- Component是定義一個(gè)對(duì)象接口, 可以給這些對(duì)象動(dòng)態(tài)添加職責(zé)
- ConcreteComponent是定義了一個(gè)具體對(duì)象, 也可以給對(duì)象添加一些職責(zé)
- Decorator 裝飾器抽象類, 繼承Component, 從外類來(lái)擴(kuò)展Component 的功能, 但是對(duì)于 Component來(lái)講, 無(wú)需知道Decorator 的存在
- ConcreteDecorator具體修飾對(duì)象, 起到給 Component 添加職責(zé)的功能
上述裝飾器模式的實(shí)現(xiàn)邏輯
#include <iostream> #include <algorithm> using namespace std;// 抽象類 class Component{ public:virtual void Operation()=0; };// 實(shí)現(xiàn) class ConcreteComponent : public Component{ public:void Operation(){cout << "原始對(duì)象 具體對(duì)象的操作/功能" << endl;} };// 抽象裝飾器 class Decorator : public Component{ protected: Component *component = nullptr; public:void SetComponent(Component *component){this->component = component;}virtual void Operation(){if(component != nullptr){cout<< "抽象修飾器先運(yùn)行完 原始對(duì)象的功能...." <<endl;component->Operation();}} };// 裝飾器A class ConcreteDecoratorA : public Decorator{ private:string addedState; public:void Operation(){// 先運(yùn)行原Component的Operation(), 在執(zhí)行本類的功能, 入addedState, 相當(dāng)于對(duì)原Component進(jìn)行了裝飾Decorator::Operation();addedState = "大爺";cout << "具體修飾對(duì)象A的操作" <<endl;} };// 裝飾器B class ConcreteDecoratorB : public Decorator{ public:void Operation(){// 先運(yùn)行原Component的Operation(), 在執(zhí)行本類的功能, 入addedState, 相當(dāng)于對(duì)原Component進(jìn)行了裝飾Decorator::Operation();cout << "具體修飾對(duì)象B的操作" <<endl;addedBehavior();}void addedBehavior(){cout << "來(lái)跟我一起跳舞" <<endl;} };int main(int argc, char const *argv[]) {ConcreteComponent *c = new ConcreteComponent();// Decorator *d1 = new ConcreteDecoratorA();// Decorator *d2 = new ConcreteDecoratorB();ConcreteDecoratorA *d1 = new ConcreteDecoratorA();ConcreteDecoratorB *d2 = new ConcreteDecoratorB();cout<< "給原始對(duì)象包裝修飾A" <<endl;d1->SetComponent(c); // A修飾器包裝ccout<< "給原始對(duì)象包裝修飾B" <<endl;d2->SetComponent(d1); // 再用B修飾器包裝ccout<< "輸出所有的對(duì)象操作情況" <<endl;d2->Operation(); // 最后在執(zhí)行結(jié)果delete c, d1, d2;return 0; }- 輸出如下
基于上面的邏輯, 對(duì)于穿衣系統(tǒng)的裝飾器模式實(shí)現(xiàn)
c 裝飾器模式下的穿衣系統(tǒng)設(shè)計(jì)
#include <iostream> #include <algorithm> using namespace std;// Person類 class Persion{ public:// Persion() : Persion("zjq"){}Persion(){}Persion(string name):name(name){}~Persion(){}virtual void show(){cout << ":裝扮的"<< name <<endl;}private:string name; };// 服飾類, 裝飾器, 需要繼承persion class Finery : public Persion{ protected:Persion *component = nullptr; // 裸體人public:Finery(){}~Finery(){}// 傳入一個(gè)人, 給這個(gè)人打扮一番void Decorator(Persion *component){this->component = component;}virtual void show(){// 這個(gè)人展示if(component != nullptr){component->show(); }else{cout << "還沒有領(lǐng)人進(jìn)入試衣間..." << endl;}}};// 具體服飾類 class Tshirts : public Finery{ public:// 初始化父類成員Tshirts(){}void show(){// cout << Decorator::component->show() << "大體恤" << endl;cout << "大體恤 ";Finery::show();} };class BigTrouser : public Finery{ public:// 初始化父類成員BigTrouser(){}void show(){// cout << Decorator::component->show() << "大體恤" << endl;cout << "大褲衩 ";Finery::show();} };int main(int argc, char const *argv[]) {Persion *xm = new Persion("小明");// Tshirts *tx = new Tshirts();// BigTrouser *bt = new BigTrouser();Finery *tx = new Tshirts();Finery *bt = new BigTrouser();tx->Decorator(xm); // 給小明穿上txbt->Decorator(tx); // 給穿了tx的小明在穿上大褲衩子bt->show();tx->Decorator(xm);bt->Decorator(tx);bt->show();delete xm, tx, bt;return 0; }- 輸出如下
總結(jié)
以上是生活随笔為你收集整理的C++设计模式 装饰器模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 考粒子静态能源公式、太阳系天体运动原理.
- 下一篇: Hilbert学习笔记