一文學會設計模式

{"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 \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 observers;\n};\n\nint main() {\n ObserverBase base1 = new ObserverFirstChild();\n ObserverBase *base2 = new ObserverSecondChild();\n\n NotifyBase notify;\n notify.Add(base2);\n notify.Add(base1);\n notify.Notify();\n notify.Remove(base1);\n notify.Notify();\n\n delete base2;\n delete base1;\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":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉個例子,有遊戲這個大類,擴展這個類的功能,有打籃球,踢足球,玩lol,玩卡丁車,可以分別定義繼承遊戲基類的四個子類,但是如果想組合這幾個功能呢,一個對象既會打籃球又會玩卡丁車,既會打籃球又會玩lol,再定義幾個類繼承遊戲基類顯然不是好的做法,裝飾器模式可以很好的解決這個問題,上代碼:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先定義一個Game基類"}]},{"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 virtual void Skill() { std::cout << \"game skill\" << std::endl; }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定義卡丁車子類和lol子類"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef _CARGAME\n#define CARGAME_\n\n#include \"game.h\"\n\nclass CarGame : public Game {\n public:\n void Skill() override { std::cout << \"car 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":"#ifndef _LOLGAME\n#define LOLGAME_\n\n#include \"game.h\"\n\nclass LolGame : public Game {\n public:\n void Skill() override { std::cout << \"lol game\" << std::endl; }\n};\n\n#endif"}]},{"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 _DECORATORGAME\n#define DECORATORGAME\n\n#include \"game.h\"\n\nclass DecoratorGame : public Game {\n protected:\n Game game;\n\n public:\n DecoratorGame(Game game) { game = game; }\n\n void Skill() override { game->Skill(); }\n\n virtual ~DecoratorGame() {}\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 BASKETBALL\n#define BASKETBALL\n\n#include \"decorator_game.h\"\n\nclass BasketBallGame : public DecoratorGame {\n public:\n BasketBallGame(Game *game) : DecoratorGame(game) {}\n\n void Skill() override {\n std::cout << \"basketball game\" << std::endl;\n DecoratorGame::Skill();\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 SOCKETBALL\n#define SOCKETBALL\n\n#include \"decorator_game.h\"\n\nclass SocketBallGame : public DecoratorGame {\n public:\n SocketBallGame(Game *game) : DecoratorGame(game) {}\n\n void Skill() override {\n std::cout << \"socket game\" << std::endl;\n DecoratorGame::Skill();\n }\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後看使用"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \"lolgame.h\"\n#include \"decoratorgame.h\"\n#include \"basketball.h\"\n#include \"cargame.h\"\n#include \"socketball.h\"\n\nint main() {\n Game lol = new LolGame();\n Game car = new CarGame();\n // 一個人既會打籃球又會打LOL可以如下使用\n Game basketballlol = new BasketBallGame(lol);\n basketballlol->Skill();\n std::cout << std::endl;\n // 一個人既會打籃球又會玩卡丁車可以如下使用\n Game basketballcar = new BasketBallGame(car);\n basketballcar->Skill();\n std::cout << std::endl;\n // 一個人既會打籃球又會玩卡丁車又會踢足球可以如下使用\n Game* g = new SocketBallGame(basketballlol);\n g->Skill();\n\n delete lol;\n delete basketballcar;\n delete basketballlol;\n delete g;\n\n return 0;\n}\n// 輸出\nbasketball game\nlol game\n\nbasketball game\ncar game\n\nsocket game\nbasketball game\nlol game"}]},{"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},"content":[{"type":"text","text":"確定好抽象部分和實現部分,將抽象部分和實現部分分離,使得他們可以獨立的變化,實現系統和抽象系統可能各自都會有各自的變化,使用橋接模式可以更加靈活的擴展,方法:用組合代替繼承。 "}]},{"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},"content":[{"type":"text","text":"首先將實現部分(畫圖)提取出來,同時多種畫圖方式從這個基類繼承後重寫,之後會作爲Shape圖形類的一個成員變量"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef _SHAPEDRAWIMPL\n#define SHAPEDRAWIMPL_\n\n#include \n\nclass ShapeDrawImpl {\n public:\n virtual void Draw() = 0;\n\n virtual ~ShapeDrawImpl() {}\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 _SHAPEDRAWIMPLRED\n#define SHAPEDRAWIMPLRED\n\n#include \"shapedraw_impl.h\"\n\nclass ShapeDrawImplRed : public ShapeDrawImpl{\n public:\n virtual void Draw() override {\n std::cout << \"draw red\" << 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 _SHAPEDRAWIMPLBLACK\n#define SHAPEDRAWIMPLBLACK\n\n#include \"shapedraw_impl.h\"\n\nclass ShapeDrawImplBlack : public ShapeDrawImpl{\n public:\n virtual void Draw() override {\n std::cout << \"draw black\" << std::endl;\n }\n};\n\n#endif"}]},{"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 SHAPE\n#define SHAPE\n\n#include \"shapedrawimpl.h\"\n\nclass Shape {\n protected:\n ShapeDrawImpl impl;\n\n public:\n virtual void Update() {}\n Shape(ShapeDrawImpl impl) : impl(impl) {}\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 _SHAPECIRCLE\n#define SHAPECIRCLE_\n\n#include \"shape.h\"\n\nclass ShapeCircle : public Shape {\npublic:\n void Update() override {\n std::cout << \"circle shape update\" << std::endl; \n impl->Draw();\n }\n\n ShapeCircle(ShapeDrawImpl *imp) : Shape(imp) {}\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 _SHAPERECTANGLE\n#define SHAPERECTANGLE_\n\n#include \"shape.h\"\n\nclass ShapeRectangle : public Shape {\n public:\n void Update() override {\n std::cout << \"rectangle shape update\" << std::endl;\n impl->Draw();\n }\n\n ShapeRectangle(ShapeDrawImpl *imp) : Shape(imp) {}\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 \"shapecircle.h\"\n#include \"shaperectangle.h\"\n#include \"shapedrawimplblack.h\"\n#include \"shapedrawimplred.h\"\n\nint main() {\n ShapeDrawImpl impl = new ShapeDrawImplBlack();\n Shape circle = new ShapeCircle(impl);\n circle->Update();\n\n delete impl;\n delete circle;\n \n return 0;\n}\n輸出:\ncircle shape update\ndraw black"}]},{"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},"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 virtual ~Game() {}\n\n virtual void Play() {\n std::cout << \"play game\" << 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 BASKETBALL\n#define BASKETBALL\n\n#include \"game.h\"\n\nclass BasketBall : public Game {\n void Play() override { std::cout << \"play basketball\" << 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 SOCKETBALL\n#define SOCKETBALL\n\n#include \"game.h\"\n\nclass SocketBall : public Game {\n void Play() override { std::cout << \"play socketball\" << std::endl; }\n};\n\n#endif"}]},{"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 _GAMEFACTORY\n#define GAMEFACTORY_\n\n#include \"game.h\"\n\nclass GameFactory {\n public:\n GameFactory() {}\n virtual ~GameFactory() {}\n\n virtual Game* CreateGame() = 0;\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 _BASKETBALLFACTORY\n#define BASKETBALLFACTORY\n\n#include \"gamefactory.h\"\n#include \"basketball.h\"\n\nclass BasketBallFactory : public GameFactory {\n public:\n Game* CreateGame() override{\n return new BasketBall();\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 _SOCKETBALLFACTORY\n#define SOCKETBALLFACTORY\n\n#include \"gamefactory.h\"\n#include \"socketball.h\"\n\nclass SocketBallFactory : public GameFactory {\n public:\n Game* CreateGame() override{\n return new SocketBall();\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 \"basketballfactory.h\"\n#include \"socketballfactory.h\"\n\nint main() {\n GameFactory factory = new BasketBallFactory();\n Game game = factory->CreateGame();\n game->Play();\n\n delete factory;\n delete game;\n\n factory = new SocketBallFactory();\n game = factory->CreateGame();\n game->Play();\n\n delete factory;\n delete game;\n\n return 0;\n}\n輸出:\nplay basketball\nplay socketball"}]},{"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":"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":"用於創建重複的對象,定義一個clone接口,通過調用clone接口創建出與原來類型相同的對象,上代碼:"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef GAME\n#define GAME\n\n#include \n\nclass Game {\n public:\n virtual Game* clone() = 0;\n\n virtual void Play() = 0;\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 BASKETBALL\n#define BASKETBALL\n\n#include \"game.h\"\n\nclass BasketBall : public Game {\n virtual Game* clone() override {\n return new BasketBall();\n }\n\n virtual void Play() override {\n std::cout << \"basketball\" << 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 \"basketball.h\"\n\nint main() {\n Game game = new BasketBall();\n game->Play();\n Game newgame = game->clone();\n newgame->Play();\n \n delete game;\n delete new_game;\n\n return 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"單純看game不知道它是什麼類型,它可能是籃球遊戲也可能是足球遊戲等,如果想創建一個與它相同類型的對象就可以使用原型模式其實就是實現一個clone接口,如果一個對象的拷貝構造函數比較複雜而自己不想使用拷貝構造的方式創建對象也可以使用原型模式,使用方式見上例。"}]},{"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},"content":[{"type":"text","text":"用於構建一個複雜的大的對象,一個複雜的對象通常需要一步步纔可以構建完成,建造者模式強調的是一步步創建對象,並通過相同的構建過程可以獲得不同的結果對象,一般來說建造者對象不是直接返回的,與抽象工廠方法區別是抽象工廠方法用於創建多個系列的對象,而建造者模式強調一步步構建對象,並且構建步驟固定,舉例:想要構建一個老師類的對象,老師有第一技能和第二技能,第一技能是數學就代表是數學老師,第一技能是英語就代表是語文老師,構造一個老師對象需要先設定老師的第一技能再設定老師的第二技能,強調一步步設定技能,將這一步步的構建過程可以抽象出建造者模式。 "}]},{"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 TEACHER\n#define TEACHER\n\n#include \n#include \n\nclass Teacher {\n private:\n std::string firstskill;\n std::string secondskill;\n\n public:\n void SetFirstSkill(const std::string& skill) { this->firstskill = skill; }\n\n void SetSecondSkill(const std::string& skill) { this->secondskill = skill; }\n};\n\n#endif"}]},{"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 _TEACHERABSTRACTBUILDER\n#define TEACHERABSTRACTBUILDER_\n\n#include \"teacher.h\"\n\nclass TeacherAbstractBuilder {\n public:\n TeacherAbstractBuilder() {}\n virtual ~TeacherAbstractBuilder() {}\n\n virtual void BuildFirstSkill() = 0;\n virtual void BuildSecondSkill() = 0;\n\n virtual Teacher* GetTeacher() = 0;\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 _MATHTEACHERBUILDER\n#define MATHTEACHERBUILDER\n\n#include \"teacherabstractbuilder.h\"\n\nclass MathTeacherBuilder : public TeacherAbstractBuilder {\n public:\n MathTeacherBuilder() { this->teacher = new Teacher(); }\n\n ~MathTeacherBuilder() { delete this->teacher; }\n\n Teacher GetTeacher() { return this->teacher; }\n\n void BuildFirstSkill() { this->teacher->SetFirstSkill(\"math\"); }\n\n void BuildSecondSkill() { this->teacher->SetSecondSkill(\"english\"); }\n\n private:\n Teacher teacher_;\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 _ENGLISHTEACHERBUILDER\n#define ENGLISHTEACHERBUILDER\n\n#include \"teacherabstractbuilder.h\"\n\nclass EnglishTeacherBuilder : public TeacherAbstractBuilder {\n public:\n EnglishTeacherBuilder() { this->teacher = new Teacher(); }\n\n ~EnglishTeacherBuilder() { delete this->teacher; }\n\n Teacher GetTeacher() { return this->teacher; }\n\n void BuildFirstSkill() { this->teacher->SetFirstSkill(\"english\"); }\n\n void BuildSecondSkill() { this->teacher->SetSecondSkill(\"math\"); }\n\n private:\n Teacher teacher_;\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定義一個穩定的Director類,由它根據具體的老師構建器決定構建哪一個老師"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef DIRECTOR\n#define DIRECTOR\n\n#include \"teacherabstractbuilder.h\"\n\nclass Director {\n public:\n Director(TeacherAbstractBuilder builder) { this->builder = builder; }\n\n ~Director() {}\n\n void Create() {\n this->builder->BuildFirstSkill();\n this->builder->BuildSecondSkill();\n }\n\n private:\n TeacherAbstractBuilder builder;\n};\n\n#endif"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用方法如下:"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \"director.h\"\n#include \"englishteacherbuilder.h\"\n#include \"mathteacherbuilder.h\"\n\nint main() {\n TeacherAbstractBuilder builder = new MathTeacherBuilder();\n Director director = new Director(builder);\n delete builder;\n delete director;\n\n builder = new EnglishTeacherBuilder();\n director = new Director(builder);\n delete builder;\n delete director;\n\n return 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過Director利用不同的具體構建器都採用相同的步驟一步步構建出不同的具體的老師類對象。"}]},{"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},"content":[{"type":"text","text":"不多說了,網上太多了,列一段單例的代碼:"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"static SingleTon& GetInstance() {\n static SingleTon t;\n return t;\n }"}]},{"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},"content":[{"type":"text","text":"通過共享技術有效支持大量細粒度的對象,主要解決面向對象代價問題,通過共享有效降低創建的對象個數,類似於對象池。 "}]},{"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 BASKETBALL\n#define BASKETBALL\n\n#include \n#include \n\nclass BasketBall {\n public:\n BasketBall(const std::string& color) : color(color) {}\n ~BasketBall() {}\n\n private:\n std::string color;\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 _BASKETBALLFACTORY\n#define BASKETBALLFACTORY\n\n#include \n#include \"basketball.h\"\n\nclass BasketballFactory {\n private:\n std::unorderedmap<:string basketball=""> map;\n\n public:\n BasketBall GetBasketBallWithColor(const std::string& color) {\n if (map.find(color) == map.end()) {\n BasketBall* p = new BasketBall(color);\n map[color] = p;\n return p;\n } else {\n return map[color];\n }\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 \"BasketballFactory.h\"\n\nint main() {\n BasketballFactory factory;\n BasketBall whiteball1 = factory.GetBasketBallWithColor(\"white\");\n BasketBall blackball1 = factory.GetBasketBallWithColor(\"black\");\n BasketBall whiteball2 = factory.GetBasketBallWithColor(\"white\");\n BasketBall blackball2 = factory.GetBasketBallWithColor(\"black\");\n std::cout << whiteball1 << std::endl;\n std::cout << whiteball2 << std::endl;\n std::cout << blackball1 << std::endl;\n std::cout << blackball2 << std::endl;\n // remember to delete\n return 0;\n}\n輸出:\n0x7fffe4984e70\n0x7fffe4984e70\n0x7fffe4984f00\n0x7fffe4984f00"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"外觀模式(Facade Pattern)"}]},{"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":"代理模式(Proxy Pattern)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲其它對象提供一種代理以控制這個對象的訪問,一般對於比較大的對象訪問比較困難或者或帶來很多麻煩,例如裸指針的使用,所以一般使用智能指針來控制裸指針,使用智能指針也是一種代理模式,舉例:A喜歡B想送給B禮物,但是卻不認識B,而C卻認識B,所以可以把C作爲A的代理去送給B禮物,代碼:"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#ifndef GIRL\n#define GIRL\n\n#include \n#include \n\nclass Girl {\n private:\n std::string name;\n\n public:\n Girl(const std::string &name) : name(name) {}\n\n std::string GetName() const noexcept { return name_; }\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 GIFT\n#define GIFT\n\n#include \"girl.h\"\n\nclass Gift {\n public:\n virtual void GiveGift() = 0;\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 _GIFTPROXY\n#define GIFTPROXY\n\n#include \"gift.h\"\n#include \"girl.h\"\n\nclass GiftProxy : public Gift {\n public:\n GiftProxy(Girl girl) : girl(girl) {}\n\n void GiveGift() override { std::cout << \"send \" << girl.GetName() << \" gift\" << std::endl; }\n\n private:\n Girl girl;\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 \"gift_proxy.h\"\n\nint main() {\n Girl lili(\"lili\");\n GiftProxy proxy(lili);\n proxy.GiveGift();\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},"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},"content":[{"type":"text","text":"使用一箇中介對象來封裝一系列的對象交互,當多個對象間互相引用且操作比較複雜時可以考慮使用中介模式。如下圖所示:左側五個對象互相依賴,通過中介這個橋樑就可以減少這個依賴。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"![d320c85de4434586e5fb5931742e6cd.jpg](https://upload-images.jianshu.io/upload_images/3725930-0dc4b653116db321.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/440)"}]},{"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},"content":[{"type":"text","text":"當一個對象的行爲依賴於它的狀態並且其有很多種狀態而且將來還會有更多狀態時,如果使用簡單的if-else來增加新狀態就違反了面向對象的開閉原則,這時可以考慮使用狀態模式,將具體的狀態做出一個抽象類,也類似於工廠模式,將具體的狀態分散於各個子類中,避免了更多的if-else分支,上代碼:"}]},{"type":"codeblock","attrs":{"lang":"cpp"},"content":[{"type":"text","text":"#include \nusing namespace std;\n\nclass Context;\nclass State {\n public:\n virtual void Handle(Context *context) = 0;\n};\n\nclass Context {\n public:\n Context(State *state) : state_(state) {}\n void Request() {\n if (state_) {\n state_->Handle(this);\n }\n }\n void ChangeState(State *pState) { state_ = pState; }\n private:\n State *state_;\n};\n\nclass ConcreteStateA : public State {\n public:\n void Handle(Context *context) override { cout << \"I am state a\" << endl; }\n};\n\nclass ConcreteStateB : public State {\n public:\n void Handle(Context *context) override { cout << \"I am state b\" << endl; }\n};\n\nint main() {\n State *state_a = new ConcreteStateA();\n State *state_b = new ConcreteStateB();\n Context *context = new Context(state_a);\n context->Request();\n context->ChangeState(state_b);\n context->Request();\n\n delete context;\n delete state_b;\n delete state_a;\n\n return 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章