Decorator裝飾器模式(C++)
阿新 • • 發佈:2018-12-16
簡而言之,它提供了一種對被裝飾者透明的方法;
例如:一篇文章本身無需知道自己的頁首和頁尾;使用者可以很方便的新增不同的頁首與頁尾 對比Strategy模式:物件需要知道使用的是哪個演算法,該方式對元件不可見,但是呼叫者可以任意數量新增裝飾。
不足:每次裝飾都會引入一個新的小物件,即使每次生成的元件類似,仍每次都新建立裝飾器,會佔用許多額外的儲存空間。
如圖,為具體的組建新增DecA與DecB裝飾
實戰:實現一個為卷子新增頁首、頁尾的簡單程式
效果:
header 2015 is added. header 'Final Test' is added. Final test starts! footer 1 is added.
關鍵語句:
WhitePaper* wp = new FooterDecorator(new HeaderDecorator(new TestPaper, "'Final Test'"),"2015"));
其中WhitePaper為整個裝飾模式中的父類 ,TestPaper為例項物件,使用Footer和Header來新增裝飾
#include <cstdio> //#include<crtdbg.h> using namespace std; /*Decorator模式: BaseClass=WhitePaper*/ class WhitePaper { public: virtual ~WhitePaper() {}; virtual void PrintContents(); }; void WhitePaper::PrintContents() { printf("This is a white paper.\n"); } /*各種裝飾器的共同父類*/ class Decorator : public WhitePaper { public: Decorator(WhitePaper *); virtual ~Decorator() { delete _wPaper; }; //!!!!!!!!!!!! virtual void PrintContents(); private: WhitePaper *_wPaper; }; Decorator::Decorator(WhitePaper* pw) { _wPaper = pw; printf("Decorator constructed.\n"); } void Decorator::PrintContents() { _wPaper->PrintContents(); } /*頁首裝飾器*/ class HeaderDecorator : public Decorator { public: HeaderDecorator(WhitePaper*, const char* str); ~HeaderDecorator() {}; virtual void PrintContents(); private: const char* s; }; HeaderDecorator::HeaderDecorator(WhitePaper* pw, const char* str):Decorator(pw){ printf("Header %s constructed.\n", str); s = str; } void HeaderDecorator::PrintContents() { printf("header %s is added.\n", this->s); Decorator::PrintContents(); } /*頁尾裝飾器*/ class FooterDecorator : public Decorator { public: FooterDecorator(WhitePaper*, int n); ~FooterDecorator() {}; virtual void PrintContents(); private: int _n; }; FooterDecorator::FooterDecorator(WhitePaper* pw, int n) :Decorator(pw) { printf("Foot constructed.\n"); _n = n; } void FooterDecorator::PrintContents() { Decorator::PrintContents(); printf("footer %d is added.\n", this->_n); } /*實體類*/ class TestPaper : public WhitePaper{ public: void PrintContents(); }; void TestPaper::PrintContents() { printf("Final test starts!\n"); } int main() { WhitePaper* wp = new TestPaper; wp = new FooterDecorator(new HeaderDecorator(new HeaderDecorator(wp, "'Final Test'"), "2015"),1); wp->PrintContents(); delete wp; getchar(); //_CrtDumpMemoryLeaks(); //檢測記憶體溢位 return 0; }
附:與堆記憶體有關的雜談
使用父類指標釋放子類物件時,父類的解構函式一定要是virtual的!!
如圖:
黑點為基類指標,V-Table表示類的虛擬函式表。若未宣告為virtual,則DecB的綠色部分和黑色部分被釋放,子類成員記憶體洩漏。宣告為virtual後解構函式被覆蓋,這樣呼叫的才是正確的版本。
從上面的記憶體情況同時可以看出,如果對pBase不作處理,則第一個實體和第二個實體仍然會陰魂不散,因為我們丟失了所有訪問它們的渠道。故Decorator的解構函式中對pBase指向的內容一定不能忘記呼叫delete。