1. 程式人生 > >C++ 設計模式--模板模式、策略模式、觀察者模式

C++ 設計模式--模板模式、策略模式、觀察者模式

## 現代軟體設計特徵:需求頻繁變化 設計模式的要點是“尋找變化點”,在變化點應用設計模式,從而更好的應對需求變化。 #### 1、 Template Method 在軟體構建結構中,往往他有整體的穩定結構,但是各個子步驟確有變化的需求,或者因為固有的原因(比如框架和應用之間)而無法和任務的整體結構同時實現。 這個時候往往使用Template Method方法。 定義一個操作中演算法的**骨架(穩定)**,而將一些步驟延遲(變化)到子類**(父類定義虛擬函式,在子類中具體實現)**。使得子類可以不改變**(複用)**一個演算法的結構即 可重定義**override**該演算法的某些特定步驟。**讓框架呼叫應用程式**而不是應用程式呼叫框架。“不要呼叫我讓我來呼叫你”,晚繫結和早繫結的區別。 #### UML類圖: ![](https://img2020.cnblogs.com/blog/1806982/202011/1806982-20201113171744079-595239258.png) 程式碼例項: ``` class Library {//穩定的資料結構,不會發生改變 public: void step1() {} int step2() { return contrl;} void virtual step3() {} void step4() {} void virtual step5() {} void run() { step1(); if(step2()) { step3(); } else { step5(); } for(int i = 10; i < 100; ++i) { step4(); } } virtual ~Library() {}; std::string name = "myname"; }; class Application1 : public Library {// 承載著不斷變化的需求 public: void step3() override { std::cout << this->name << std::endl; } void step5() override { std::cout << this->Library::name << std::endl; } std:: string name = "Application"; }; class Application2 : public Library {// 承載者不斷變化的需求 public: void step3() override {} void step5() override {} }; int main() { Library *a = new Application1; a->run(); delete a; return 0; } ``` #### 2、 策略模式(Strategy) 在軟體構建的過程中,某些物件使用的演算法可能多種多樣,經常改變,如果將這些演算法都編碼到物件中去,將會使得物件變得異常複雜,而且有時候支援幾乎不使用的演算法也是一種效能負擔。 ###### 問題:如何在執行的時候根據需要透明的改變演算法? 將演算法與物件本身解耦合,從而避免上述問題? ##### 定義:定義一系列演算法,將他們一個個封裝起來,而且他們可以相互替換**(變化)**。該模式使得演算法可以獨立於使用他們的應用程式**(穩定)**而變化**(擴張,子類化)** #### UML類圖: ![](https://img2020.cnblogs.com/blog/1806982/202011/1806982-20201116111929867-1298963529.png) 程式碼例項: ``` class Strategy { public: virtual int doOperation(int num1, int num2) {} // 基類中需要改寫的方法 virtual ~Strategy(){} }; class plus final : public Strategy {// 不同的策略 public: int doOperation(int num1, int num2) { return num1 + num2; } }; class multipl final : public Strategy { public: int doOperation(int num1, int num2) { return num1 * num2; } }; class minus final : public Strategy { public: int doOperation(int num1, int num2) { return num1 - num2; } }; class Context { //封裝呼叫介面 public: Context(Strategy *init) :stra(init) {} int run(int num1, int num2) { return this->
stra->doOperation(num1, num2); } private: Strategy *stra; }; int main() { Context demo(new multipl); std::cout << demo.run(10, 20) << std::endl; //使用呼叫介面中的基類指標多型的執行。 return 0; } ``` #### 3、 觀察者模式(Observer) 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的物件中使它們可以各自獨立地改變和複用。 一個物件的改變將導致其他一個或多個物件也發生改變,而不知道具體有多少物件將發生改變,可以降低物件之間的耦合度。 一個物件必須通知其他物件,而並不知道這些物件是誰。 ##### 定義:定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。 #### UML類圖: ![](https://img2020.cnblogs.com/blog/1806982/202011/1806982-20201116142313742-13140957.png) #### 程式碼示例: ``` enum class msg { RETURN1, RETURN2, RETURN3 }; class Observer { public: void virtual update(msg ms) = 0; }; class ob1 : public Observer { public: void update(msg ms) { switch(ms) { case msg::RETURN1 : case msg::RETURN2 : case msg::RETURN3 : std::cout << "RETURN1" << std::endl; default: std::cout << "right" << std::endl; } } }; class ob2 : public Observer { public: void update(msg ms) { switch(ms) { case msg::RETURN1 : case msg::RETURN2 : case msg::RETURN3 : { std::cout << "RETURN2" << std::endl; break; } default: std::cout << "erro ms2" << std::endl; } } }; class ob3 : public Observer { public: void update(msg ms) { switch(ms) { case msg::RETURN1 : case msg::RETURN2 : case msg::RETURN3 : { std::cout << "RETURN3" << std::endl; break; } default: std::cout << "erro ms3" << std::endl; } } }; class subject { public: void addob(Observer *ob) { obs.insert(ob);} void removeob(Observer *ob) { auto rob = obs.find(ob); if(rob != obs.end()){ obs.erase(ob); } else std::cout << "erro no matching observer" << std::endl; } void update() { for(auto& ob : obs) { ob->update(ms); } } msg ms; std::set obs; }; int main() { Observer *ob_1 = new ob1; Observer *ob_2 = new ob2; Observer *ob_3 = new ob3; subject *sub = new subject; sub->ms = msg::RETURN1; sub->addob(ob_1); sub->addob(ob_2); sub->addob(ob_3); sub->update(); return 0; } ``` observer:變化儘量通過呼叫方的多型機制,傳遞給被呼叫方,決定如何呼叫。