namespace _nmsp1 { //抽象的控制元件類 class Control { public: virtual void draw() = 0; //draw方法,用於將自身繪製到螢幕上。 public: virtual ~Control() {} //做父類時解構函式應該為虛擬函式 }; //列表控制元件類 class ListCtrl :public Control { public: virtual void draw() { cout << "繪製普通的列表控制元件!" << endl; //具體可以用DirectX或OpenGL來繪製 } }; //抽象的裝飾器類 class Decorator :public Control { public: Decorator(Control* tmpctrl) :m_control(tmpctrl) {} //建構函式 virtual void draw() { m_control->draw(); //虛擬函式,呼叫的是哪個draw,取決於m_control指向的物件 } private: Control* m_control; //需要被裝飾的其他控制元件,這裡用的是Control *; }; //---------------------- //具體的“邊框”裝飾器類 class BorderDec :public Decorator { public: BorderDec(Control* tmpctrl) :Decorator(tmpctrl) {} //建構函式 virtual void draw() { Decorator::draw(); //呼叫父類的draw方法以保持以往已經繪製出的內容 drawBorder(); //也要繪製自己的內容 } private: void drawBorder() { cout << "繪製邊框!" << endl; } }; //具體的“垂直捲軸”裝飾器類 class VerScrollBarDec :public Decorator { public: VerScrollBarDec(Control* tmpctrl) :Decorator(tmpctrl) {} //建構函式 virtual void draw() { Decorator::draw(); //呼叫父類的draw方法以保持以往已經繪製出的內容 drawVerScrollBar(); //也要繪製自己的內容 } private: void drawVerScrollBar() { cout << "繪製垂直捲軸!" << endl; } }; //具體的“水平捲軸”裝飾器類 class HorScrollBarDec :public Decorator { public: HorScrollBarDec(Control* tmpctrl) :Decorator(tmpctrl) {} //建構函式 virtual void draw() { Decorator::draw(); //呼叫父類的draw方法以保持以往已經繪製出的內容 drawHorScrollBar(); //也要繪製自己的內容 } private: void drawHorScrollBar() { cout << "繪製水平捲軸!" << endl; } }; } int main() { //(1)建立一個又帶邊框,又帶垂直捲軸的列表控制元件 //首先繪製普通的列表控制元件 _nmsp1::Control* plistctrl = new _nmsp1::ListCtrl(); //本體 //接著“藉助普通的列表控制元件”,可以透過邊框裝飾器繪製出一個“帶邊框的列表控制元件” _nmsp1::Decorator* plistctrl_b = new _nmsp1::BorderDec(plistctrl); //_nmsp1::Decorator*用成_nmsp1::Control * //接著“藉助帶邊框的列表控制元件”,就可以透過垂直捲軸裝飾器繪製出一個“帶垂直捲軸又帶邊框的列表控制元件” _nmsp1::Decorator* plistctrl_b_v = new _nmsp1::VerScrollBarDec(plistctrl_b); plistctrl_b_v->draw(); //這裡完成最終繪製 cout << "--------------------" << endl; //(2)建立一個只帶水平捲軸的列表控制元件 //首先繪製普通的列表控制元件 _nmsp1::Control* plistctrl2 = new _nmsp1::ListCtrl(); //本體 //接著“藉助普通的列表控制元件”,可以透過水平捲軸裝飾器繪製出一個“帶水平捲軸的列表控制元件” _nmsp1::Decorator* plistctrl2_h = new _nmsp1::HorScrollBarDec(plistctrl2); plistctrl2_h->draw(); //(3)釋放資源 delete plistctrl_b_v; delete plistctrl_b; delete plistctrl; delete plistctrl2_h; delete plistctrl2; }
裝飾(Decorator)模式:裝飾器模式/包裝模式,結構型模式
namespace _nmsp2 { //抽象飲料類 class Beverage { public: virtual int getprice() = 0; //獲取價格 public: virtual ~Beverage() {} }; //水果飲料類 class FruitBeverage : public Beverage { public: virtual int getprice() { return 10; //一杯單純的水果飲料,售價為10元 } }; //抽象的裝飾器類 class Decorator :public Beverage { public: Decorator(Beverage* tmpbvg) :m_pbvg(tmpbvg) {} //建構函式 virtual int getprice() { return m_pbvg->getprice(); } private: Beverage* m_pbvg; }; //具體的“砂糖”裝飾器類 class SugarDec :public Decorator { public: SugarDec(Beverage* tmpbvg) :Decorator(tmpbvg) {} //建構函式 virtual int getprice() { return Decorator::getprice() + 1; //額外加多1元,要呼叫父類的getprice方法以把以往的價格增加進來 } }; //具體的“牛奶”裝飾器類 class MilkDesc :public Decorator { public: MilkDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //建構函式 virtual int getprice() { return Decorator::getprice() + 2; //額外加多2元,要呼叫父類的getprice方法以把以往的價格增加進來 } }; //具體的“珍珠”裝飾器類 class BubbleDesc :public Decorator { public: BubbleDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //建構函式 virtual int getprice() { return Decorator::getprice() + 2; //額外加多2元,要呼叫父類的getprice方法以把以往的價格增加進來 } }; } int main() { //建立一杯單純的水果飲料,價格10元: _nmsp2::Beverage* pfruit = new _nmsp2::FruitBeverage(); //向飲料中增加珍珠,價格多加了2元 _nmsp2::Decorator *pfruit_addbubb = new _nmsp2::BubbleDesc(pfruit); //再向飲料中增加砂糖,價格又加多了1元 _nmsp2::Decorator* pfruit_addbubb_addsugar = new _nmsp2::SugarDec(pfruit_addbubb); //輸出最終的價格 cout << "加了珍珠又加了砂糖的水果飲料最終價格是:" << pfruit_addbubb_addsugar->getprice() << "元人民幣" << endl; //釋放資源 delete pfruit_addbubb_addsugar; delete pfruit_addbubb; delete pfruit; return 0; }
代理模式
namespace _nmsp1 { class WebAddr { public: virtual void visit() = 0; //執行訪問網站的動作,子類中會重新實現 virtual ~WebAddr() {} //做父類時解構函式應該為虛擬函式 }; //某購物網站 class WebAddr_Shopping :public WebAddr { public: virtual void visit() { //......訪問該購物網站,可能涉及複雜的網路通訊 cout << "訪問WebAddr_Shopping購物網站!" << endl; } }; //某影片網站 class WebAddr_Video :public WebAddr { public: virtual void visit() { //......訪問該影片網站,可能涉及複雜的網路通訊 cout << "訪問WebAddr_Video影片網站!" << endl; } }; //------------------------- //網站程式碼類 class WebAddrProxy :public WebAddr { public: //建構函式,引入的目的是傳遞進來要訪問的具體網站 WebAddrProxy(WebAddr* pwebaddr) :mp_webaddr(pwebaddr) {} public: virtual void visit() { //在這裡進行訪問的合法性檢查,日誌記錄或者流量限制...... mp_webaddr->visit(); //在這裡可以進行針對返回資料的過濾...... } private: WebAddr* mp_webaddr; //程式碼要訪問的具體網站 }; //----------------- //專門針對某購物網站WebAddr_Shopping的代理 class WebAddr_Shopping_Proxy :public WebAddr { public: virtual void visit() { //在這裡進行訪問的合法性檢查,日誌記錄或者流量限制...... WebAddr_Shopping* p_webaddr = new WebAddr_Shopping(); p_webaddr->visit(); //在這裡可以進行針對返回資料的過濾...... //釋放資源 delete p_webaddr; } }; } int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程式退出時檢測記憶體洩漏並顯示到“輸出”視窗 _nmsp1::WebAddr* wba1 = new _nmsp1::WebAddr_Shopping(); wba1->visit(); //訪問該購物網站 _nmsp1::WebAddr* wba2 = new _nmsp1::WebAddr_Video(); wba2->visit(); //訪問該影片網站 //資源釋放 delete wba1; delete wba2; /* _nmsp1::WebAddr* wba1 = new _nmsp1::WebAddr_Shopping(); _nmsp1::WebAddr* wba2 = new _nmsp1::WebAddr_Video(); _nmsp1::WebAddrProxy* wbaproxy1 = new _nmsp1::WebAddrProxy(wba1); wbaproxy1->visit(); //透過代理去訪問WebAddr_Shopping購物網站 _nmsp1::WebAddrProxy* wbaproxy2 = new _nmsp1::WebAddrProxy(wba2); wbaproxy2->visit(); //透過代理去訪問WebAddr_Video影片購物網站 //資源釋放 delete wba1; delete wba2; //資源釋放 delete wbaproxy1; delete wbaproxy2; */ /* _nmsp1::WebAddr_Shopping_Proxy* wbasproxy = new _nmsp1::WebAddr_Shopping_Proxy(); wbasproxy->visit(); //訪問實際的購物網站 //資源釋放 delete wbasproxy; */ return 0; }
namespace _nmsp2 { //快取/緩衝代理(Cache Proxy)範例 vector<string> g_fileItemList; //抽象主題 class ReadInfo { public: virtual void read() = 0; virtual ~ReadInfo() {} }; //真實主題 class ReadInfoFromFile : public ReadInfo { public: virtual void read() //從檔案中讀資訊(讀取test.txt的內容) { ifstream fin("test.txt"); if (!fin) { cout << "檔案開啟失敗" << endl; return; } string linebuf; while (getline(fin, linebuf)) //從哪個檔案中逐行讀入內容 { if (!linebuf.empty()) //讀的不是空行 { g_fileItemList.push_back(linebuf); //將檔案中的每一行都儲存到vector容器中。 //cout << linebuf << endl; } } fin.close(); //關閉檔案輸入流 } }; //代理主題 class ReadInfoProxy :public ReadInfo { public: virtual void read() { if (!m_loaded) { //沒有從檔案中載入資訊,則載入 m_loaded = true; //標記已經從檔案中載入資訊了 cout << "從檔案中讀取了如下資料---------:" << endl; ReadInfoFromFile* rf = new ReadInfoFromFile(); rf->read(); //將檔案中的資料讀入全域性容器g_fileItemList delete rf; //釋放資源 } else { cout << "從快取中讀取了如下資料----------:" << endl; } //現在資料一定在g_fileItemList中,開始顯示 for (auto iter = g_fileItemList.begin(); iter != g_fileItemList.end(); ++iter) { cout << *iter << endl; } } private: bool m_loaded = false; //false表示還沒有從檔案中讀出資料到記憶體 }; } int main() { _nmsp2::ReadInfo* preadinfoproxy = new _nmsp2::ReadInfoProxy(); preadinfoproxy->read(); //第一次呼叫read是藉助代理使用真實主題到檔案中拿資料 preadinfoproxy->read(); //後續呼叫read都是直接從快取中拿資料 preadinfoproxy->read(); //從快取中拿資料 //資源釋放 delete preadinfoproxy; system("pause"); return 0; }
裝飾器模式和代理模式在設計模式中有不同的應用場景和作用。
裝飾器模式(Decorator Pattern)主要用於動態地給物件新增額外的職責。它允許向一個現有的物件新增新的功能,而無需改變其結構。裝飾器模式透過建立一個裝飾器類,該類實現了與被裝飾物件相同的介面,並在內部持有一個被裝飾物件的例項,從而可以動態地新增新的功能。這樣就可以在執行時動態地新增、移除或者組合物件的行為,而不影響其原始行為。
代理模式(Proxy Pattern)則是用一個代理物件來控制對原始物件的訪問。代理模式可以用於控制對物件的訪問,以實現對原始物件的操作的增強、延遲載入或者許可權控制。代理模式常見的應用包括遠端代理、虛擬代理、保護代理等。代理物件通常會持有對真實物件的引用,並在對真實物件的訪問上進行控制,例如在對真實物件的請求前後執行額外的邏輯。
因此,裝飾器模式主要用於動態地擴充套件物件的功能,而代理模式主要用於控制對物件的訪問。兩種模式在應用場景和解決問題上有一定的差異,但都能夠提供靈活性和可維護性。
當使用C++實現裝飾器模式時,我們可以考慮一個簡單的示例:假設我們有一個Shape
介面和其具體實現類Circle
,現在我們希望能夠動態地給Circle
新增額外的功能,比如顏色或者邊框。這時候就可以使用裝飾器模式。
首先,我們定義Shape
介面及其具體實現類Circle
:
// Shape介面
class Shape {
public:
virtual void draw() = 0;
};
// 具體的形狀類:圓形
class Circle : public Shape {
public:
void draw() override {
std::cout << "畫一個圓形" << std::endl;
}
};
然後,我們建立一個裝飾器類ShapeDecorator
,用於動態地新增額外的功能。這裡以新增顏色為例:
// 裝飾器類
class ShapeDecorator : public Shape {
protected:
Shape* decoratedShape;
public:
ShapeDecorator(Shape* shape) : decoratedShape(shape) {}
void draw() override {
decoratedShape->draw();
}
};
// 具體的裝飾器類:新增顏色
class ColorDecorator : public ShapeDecorator {
private:
std::string color;
public:
ColorDecorator(Shape* shape, const std::string& col) : ShapeDecorator(shape), color(col) {}
void draw() override {
decoratedShape->draw();
std::cout << "顏色: " << color << std::endl;
}
};
使用裝飾器模式,我們可以這樣來使用:
int main() {
// 建立一個原始的圓形物件
Shape* circle = new Circle();
// 使用裝飾器來動態地新增顏色
Shape* redCircle = new ColorDecorator(circle, "紅色");
redCircle->draw();
delete circle;
delete redCircle;
return 0;
}
在這個示例中,我們透過裝飾器模式動態地給Circle
物件新增了顏色的功能,而不需要修改Circle
類的結構。
當使用C++實現裝飾器模式時,我們可以考慮一個簡單的示例:假設我們有一個Shape
介面和其具體實現類Circle
,現在我們希望能夠動態地給Circle
新增額外的功能,比如顏色或者邊框。這時候就可以使用裝飾器模式。
首先,我們定義Shape
介面及其具體實現類Circle
:
// Shape介面
class Shape {
public:
virtual void draw() = 0;
};
// 具體的形狀類:圓形
class Circle : public Shape {
public:
void draw() override {
std::cout << "畫一個圓形" << std::endl;
}
};
然後,我們建立一個裝飾器類ShapeDecorator
,用於動態地新增額外的功能。這裡以新增顏色為例:
// 裝飾器類
class ShapeDecorator : public Shape {
protected:
Shape* decoratedShape;
public:
ShapeDecorator(Shape* shape) : decoratedShape(shape) {}
void draw() override {
decoratedShape->draw();
}
};
// 具體的裝飾器類:新增顏色
class ColorDecorator : public ShapeDecorator {
private:
std::string color;
public:
ColorDecorator(Shape* shape, const std::string& col) : ShapeDecorator(shape), color(col) {}
void draw() override {
// 呼叫被裝飾物件的draw方法
decoratedShape->draw();
// 新增額外的功能:顏色
std::cout << "顏色: " << color << std::endl;
}
};
使用裝飾器模式,我們可以這樣來使用:
int main() {
// 建立一個原始的圓形物件
Shape* circle = new Circle();
// 使用裝飾器來動態地新增顏色
Shape* redCircle = new ColorDecorator(circle, "紅色");
redCircle->draw();
delete circle;
delete redCircle;
return 0;
}
在這個示例中,我們透過裝飾器模式動態地給Circle
物件新增了顏色的功能,而不需要修改Circle
類的結構。這樣做的好處在於,可以在執行時動態地新增新的功能,而且還能保持類的單一職責原則,使得程式碼更加靈活和可維護。
當使用C++實現代理模式時,我們可以考慮一個簡單的示例:假設我們有一個介面Image
和其具體實現類RealImage
,現在我們希望能夠透過代理來控制對RealImage
物件的訪問。這時候就可以使用代理模式。
首先,我們定義Image
介面及其具體實現類RealImage
:
// Image介面
class Image {
public:
virtual void display() = 0;
};
// 具體的影像類:實際影像
class RealImage : public Image {
private:
std::string filename;
public:
RealImage(const std::string& file) : filename(file) {}
void display() override {
std::cout << "顯示影像: " << filename << std::endl;
}
};
然後,我們建立一個代理類ProxyImage
,用於控制對RealImage
物件的訪問:
// 代理類
class ProxyImage : public Image {
private:
std::string filename;
RealImage* realImage;
void loadImage() {
if (realImage == nullptr) {
realImage = new RealImage(filename);
}
}
public:
ProxyImage(const std::string& file) : filename(file), realImage(nullptr) {}
void display() override {
loadImage();
realImage->display();
}
};
使用代理模式,我們可以這樣來使用:
int main() {
// 使用代理來控制對RealImage物件的訪問
Image* image = new ProxyImage("test.jpg");
// 第一次訪問,會載入真實影像
image->display();
// 第二次訪問,不需要重新載入真實影像
image->display();
delete image;
return 0;
}
在這個示例中,我們透過代理模式控制了對RealImage
物件的訪問。代理類ProxyImage
負責在必要時建立並管理RealImage
物件,並在適當的時機呼叫RealImage
物件的方法。透過代理模式,我們可以實現延遲載入、訪問控制等功能,而不需要直接訪問RealImage
物件。