- \n#include \"observerfirstchild.h\"\n#include \"observersecondchild.h\"\n\nclass NotifyBase {\n public:\n void Add(ObserverBase ob) { observers.emplace_back(ob); };\n\n void Remove(ObserverBase ob) { observers.remove(ob); }\n\n void Notify() {\n for (auto observer : observers) {\n observer->Update();\n }\n }\n\n private:\n std::list
一文學會設計模式
{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近在研究設計模式,發現儘管設計模式是針對面嚮對象語言提出的,但貌似市面上大多數都是基於java給出的例子,C++的例子極少,自己看完李建忠老師的GOF設計模式視頻後查閱各種資料並結合自身實踐總結如下,希望對大家有所幫助。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"設計模式簡介"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設計模式是主要針對面嚮對象語言提出的一種設計思想,主要是提高代碼可複用性,抵禦變化,儘量將變化所帶來的影響降到最低。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"面向對象特點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","content":[{"type":"text","text":"封裝:隱藏內部實現"}]}]},{"type":"listitem","content":[{"type":"paragraph","content":[{"type":"text","text":"繼承:複用現有的代碼"}]}]},{"type":"listitem","content":[{"type":"paragraph","content":[{"type":"text","text":"多態:改寫對象的行爲"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"面向對象設計原則"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"依賴倒置原則:針對接口編程,依賴於抽象而不依賴於具體,抽象(穩定)不應依賴於實現細節(變化),實現細節應該依賴於抽象,因爲穩定態如果依賴於變化態則會變成不穩定態。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"開放封閉原則:對擴展開放,對修改關閉,業務需求是不斷變化的,當程序需要擴展的時候,不要去修改原來的代碼,而要靈活使用抽象和繼承,增加程序的擴展性,使易於維護和升級,類、模塊、函數等都是可以擴展的,但是不可修改。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"單一職責原則:一個類只做一件事,一個類應該僅有一個引起它變化的原因,並且變化的方向隱含着類的責任。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"里氏替換原則:子類必須能夠替換父類,任何引用基類的地方必須能透明的使用其子類的對象,開放關閉原則的具體實現手段之一。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"接口隔離原則:接口最小化且完備,儘量少public來減少對外交互,只把外部需要的方法暴露出來。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"最少知道原則:一個實體應該儘可能少的與其他實體發生相互作用。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"text","text":"將變化的點進行封裝,做好分界,保持一側變化,一側穩定,調用側永遠穩定,被調用測內部可以變化。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":8,"align":null,"origin":null},"content":[{"type":"text","text":"優先使用組合而非繼承,繼承爲白箱操作,而組合爲黑箱,繼承某種程度上破壞了封裝性,而且父類與子類之間耦合度比較高。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":9,"align":null,"origin":null},"content":[{"type":"text","text":"針對接口編程,而非針對實現編程,強調"},{"type":"text","marks":[{"type":"strong"}],"text":"接口標準化"},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"小總結: 沒有一步到位的設計模式,剛開始編程時不要把太多精力放到設計模式上,需求總是變化的,剛開始着重於實現,一般敏捷開發後爲了應對變化重構再決定採取合適的設計模式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"模板方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"父類定義算法的骨架,而將一些步驟延遲到子類去實現,使得子類可以複用骨架,並附加特性,以開發框架舉例,框架開發人員把框架調用流程定好,而將某些具體的步驟作爲虛函數留給子類去重寫,話不多說,上代碼。"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef GAME\n#define GAME\n\n#include \n\nclass Game {\n public:\n Game() {}\n\n virtual ~Game() {}\n\n void Run() {\n InitGame();\n StartGame();\n StopGame();\n }\n\n protected:\n virtual void StartGame() { std::cout << \"step 2: start game\" << std::endl; }\n\n private:\n void InitGame() { std::cout << \"step 1: init game\" << std::endl; }\n void StopGame() { std::cout << \"step 3: stop game\" << std::endl; }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \"game.h\"\n\nclass BasketBall : public Game {\n void StartGame() override { std::cout << \"start basketball game\" << std::endl; }\n};"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \"game.h\"\n\nclass SocketBall : public Game {\n void StartGame() override { std::cout << \"start socketball game\" << std::endl; }\n};"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \"basketball.h\"\n#include \"socketball.h\"\n\nint main() {\n Game game = new BasketBall();\n game->Run();\n delete game;\n Game game2 = new SocketBall();\n game2->Run();\n delete game2;\n return 0;\n}\ng++ test.cc -std=c++11 && ./a.out\n輸出:\nstep 1: init game\nstart basketball game\nstep 3: stop game\nstep 1: init game\nstart socketball game\nstep 3: stop game"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼很簡單,體現的是思想,遊戲包含三個步驟,初始化遊戲,開始遊戲,停止遊戲,初始化遊戲和停止遊戲步驟比較統一,由父類Game定義好,而開始遊戲是第二個步驟,可以有打籃球和踢足球,將來也可以有羽毛球,乒乓球等等,每增加一項運動,都可以從Game父類中繼承後重寫開始遊戲這個函數,達到不同的功能,符合"},{"type":"text","marks":[{"type":"strong"}],"text":"模板方法"},{"type":"text","text":"的特性,即"},{"type":"text","marks":[{"type":"strong"}],"text":"如何在確定穩定結構前提下,應對子步驟需求的變化"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"策略模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定義一系列的算法,將它們一個個封裝,使得他們可以相互替換,一般爲了解決多個if-else帶來的複雜性,在多種算法相似的情況下,通過策略模式可減少if-else帶來的複雜性和難以維護性,一般在項目中發現多個if-else並且預感將來還會在此增加if-else分支,那基本上就需要使用策略模式。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先舉一個不使用策略模式的例子,拿計算來說,下面代碼定義了加法操作和減法操作,以後如果需要增加乘法除法等計算,那就需要在枚舉裏添加新類型,並且增加if-else分支,這違反了開放關閉原則。"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"enum class CalOperation {\n add,\n sub\n};\n\nint NoStragegy(CalOperation ope) {\n if (ope == CalOperation::add) {\n std::cout << \"this is add operation\" << std::endl;\n } else if (ope == CalOperation::sub) {\n std::cout << \"this is sub operation\" << std::endl;\n } // 如何將來需要增加乘法或者除法或者其它運算,還需要增加if-else\n return 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下例爲使用策略模式,定義一個基類Calculation,包含虛函數operation()。"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef CALCULATION\n#define CALCULATION\n\n#include \n\nclass Calculation {\n public:\n Calculation() {}\n\n virtual ~Calculation() {}\n\n virtual void operation() { std::cout << \"base operation\" << std::endl; }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每增加一種運算,就增加一個繼承基類的子類,重寫operation()函數。"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef ADD\n#define ADD\n\n#include \"calculation.h\"\n\nclass Add : public Calculation {\n void operation() override { std::cout << \"this is add operation\" << std::endl; }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef SUB\n#define SUB\n\n#include \"calculation.h\"\n\nclass Sub : public Calculation {\n void operation() override { std::cout << \"this is sub operation\" << std::endl; }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"int Stragegy() {\n Calculation cal = new Add();\n cal->operation();\n delete cal;\n\n Calculation cal2 = new Sub(); // 這裏將來都可以用工廠模式改掉,不會違反開放封閉原則\n cal2->operation();\n delete cal2;\n\n return 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是不是方便了很多,將來如果有乘法除法和其它運算規則,只需要再加一個繼承基類的子類即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"觀察者模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定義對象間的一對多關係,當一個對象狀態發生改變的時候,其它依賴於它的對象都會得到廣播通知並進行自定義動作,通過面向對象技術的多態技術,可以降低這種依賴關係,降低耦合度,上代碼."}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef OBSERVER\n#define OBSERVER\n\n#include \n\nclass ObserverBase {\n public:\n ObserverBase() {}\n virtual ~ObserverBase() {}\n\n virtual void Update() {}\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef _OBSERVERFIRSTCHILD\n#define OBSERVERFIRSTCHILD_\n\n#include \"observer.h\"\n\nclass ObserverFirstChild : public ObserverBase {\n void Update() override {\n std::cout << \"first child receive notify\" << std::endl;\n }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef _OBSERVERSECONDCHILD\n#define OBSERVERSECONDCHILD_\n\n#include \"observer.h\"\n\nclass ObserverSecondChild : public ObserverBase {\n void Update() override {\n std::cout << \"second child receive notify\" << std::endl;\n }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.