设计模式5 行为模式
設計模式5 行為模式
模板方法模式:沖咖啡,沖茶水
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std;//抽象的制作飲料方法 class?MakeDrink { public://1?把水煮開void?boil()?{cout?<<?"把水煮開"?<<?endl;}//2?沖某物virtual?void?brew()?=?0;//3?從大杯倒入小杯void?putInCup(){cout?<<?"把沖泡好的飲料?從大杯倒入小杯"?<<?endl;}//4?加一些酌料virtual?void?addThings()?=?0;//鉤子函數,?hookvirtual?bool?CustomWantAddThings()?{return?true;}//業務的邏輯的統一模板?void?make()?{boil();brew();?//子類putInCup();?if?(CustomWantAddThings()?==?true)?{addThings();?//子類的多態}} };//制作咖啡 class?MakeCoffee?:public?MakeDrink { public:MakeCoffee(bool?isAdd){this->isAdd?=?isAdd;}//2?沖某物virtual?void?brew(){cout?<<?"沖泡咖啡豆"?<<?endl;}//4?加一些酌料virtual?void?addThings()??{cout?<<?"添加糖和牛奶"?<<?endl;}virtual?bool?CustomWantAddThings()?{return?isAdd;}private:bool?isAdd; };//沖泡茶葉 class?MakeTea?:public?MakeDrink { public:MakeTea(bool?isAdd){this->isAdd?=?isAdd;}//2?沖某物virtual?void?brew()?{cout?<<?"沖泡?茶葉"?<<?endl;}//4?加一些酌料virtual?void?addThings()??{cout?<<?"添加?檸檬?或者?菊花"?<<?endl;}virtual?bool?CustomWantAddThings()?{return?isAdd;}private:bool?isAdd; };int?main(void) {MakeDrink?*makeCoffee?=?new?MakeCoffee(true);makeCoffee->make();cout?<<?"?------?"?<<?endl;MakeDrink?*makeTea?=?new?MakeTea(false);makeTea->make();return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? 把水煮開 沖泡咖啡豆 把沖泡好的飲料?從大杯倒入小杯 添加糖和牛奶------? 把水煮開 沖泡?茶葉 把沖泡好的飲料?從大杯倒入小杯 chunli@linux:~$模板方法模式中的角色和職責?
? AbstractClass(抽象類):在抽象類中定義了一系列基本操作
(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一
個基本操作對應算法的一個步驟,在其子類中可以重定義或實現這些步驟。同
時,在抽象類中實現了一個模板方法(Template Method),用于定義一個算法
的框架,模板方法不僅可以調用在抽象類中實現的基本方法,也可以調用在抽
象類的子類中實現的基本方法,還可以調用其他對象中的方法。?
? ? ? ?ConcreteClass(具體子類): 它是抽象類的子類,用于實現在父類中聲
明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經實現
的具體基本操作。?
模板方法的優缺點?
優點:?
? ? ? ?(1) 在父類中形式化地定義一個算法,而由它的子類來實現細節的處理,在
子類實現詳細的處理算法時并不會改變算法中步驟的執行次序。?
? ? ? ?(2) 模板方法模式是一種代碼復用技術,它在類庫設計中尤為重要,它提取
了類庫中的公共行為,將公共行為放在父類中,而通過其子類來實現不同的行
為,它鼓勵我們恰當使用繼承來實現代碼復用。?
? ? ? ?(3) 可實現一種反向控制結構,通過子類覆蓋父類的鉤子方法來決定某一特
定步驟是否需要執行。?
? ? ? ?(4) 在模板方法模式中可以通過子類來覆蓋父類的基本方法,不同的子類可
以提供基本方法的不同實現,更換和增加新的子類很方便,符合單一職責原則
和開閉原則。?
??
缺點:?
? ? ? ?需要為每一個基本方法的不同實現提供一個子類,如果父類中可變的基本
方法太多,將會導致類的個數增加,系統更加龐大,設計也更加抽象。
適用場景?
? (1)具有統一的操作步驟或操作過程;?
?(2) 具有不同的操作細節;?
?(3) 存在多個具有同樣操作步驟的應用場景,但某些具體的操作細節卻各
不相同;?
? ?在抽象類中統一操作步驟,并規定好接口;讓子類實現接口。這樣
可以把各個具體的子類和操作步驟解耦合。?
命令模式:病人看病直接找醫生,耦合度太高.
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std; class?Doctor { public:void?treatEyes(){cout?<<"treat?eyes?"?<<?endl;}void?treatNose(){cout?<<"treat?nose"?<<?endl;} };int?main(void) {Doctor?*doctor?=?new?Doctor;doctor->treatEyes();doctor->treatNose();return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? treat?eyes? treat?nose chunli@linux:~$拿著病單來看醫生,醫生只跟病單打交道
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std; class?Doctor { public:void?treatEyes(){cout?<<"treat?eyes?"?<<?endl;}void?treatNose(){cout?<<"treat?nose"?<<?endl;} };class?CommandEyes { public:CommandEyes(Doctor*?doctor){this->doctor?=?doctor;}~CommandEyes(){if(this->doctor?!=?NULL){delete?this->doctor;this->doctor?=?NULL;}}void?treat(){this->doctor->treatEyes();} private:Doctor?*doctor; };class?CommandNose { public:CommandNose(Doctor*?doctor){this->doctor?=?doctor;}~CommandNose(){if(this->doctor?!=?NULL){delete?this->doctor;this->doctor?=?NULL;}}void?treat(){this->doctor->treatNose();} private:Doctor?*doctor; };int?main(void) {//拿著病單來看醫生CommandEyes?*commandEyes??=new?CommandEyes(new?Doctor);commandEyes->treat();CommandNose?*commandNose??=new?CommandNose(new?Doctor);commandNose->treat();return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? treat?eyes? treat?nose chunli@linux:~$將病單抽象出來
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std; class?Doctor { public:void?treatEyes(){cout?<<"treat?eyes?"?<<?endl;}void?treatNose(){cout?<<"treat?nose"?<<?endl;} };class?Command { public:Command(Doctor?*doctor){this->doctor?=?doctor;}~Command(){if(this->doctor?!=?NULL){delete?this->doctor;this->doctor?=?NULL;}}virtual?void?treat()?=?0; protected:Doctor?*doctor; };class?CommandEyes:public?Command { public:CommandEyes(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatEyes();} };class?CommandNose:public?Command { public:CommandNose(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatNose();} };int?main(void) {Command?*comd1??=new?CommandEyes(new?Doctor);comd1->treat();Command?*comd2??=new?CommandNose(new?Doctor);comd2->treat();return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? treat?eyes? treat?nose chunli@linux:~$讓護士接病單,通知病人來看病:
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std; class?Doctor { public:void?treatEyes(){cout?<<"treat?eyes?"?<<?endl;}void?treatNose(){cout?<<"treat?nose"?<<?endl;} };class?Command { public:Command(Doctor?*doctor){this->doctor?=?doctor;}~Command(){if(this->doctor?!=?NULL){delete?this->doctor;this->doctor?=?NULL;}}virtual?void?treat()?=?0; protected:Doctor?*doctor; };class?CommandEyes:public?Command { public:CommandEyes(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatEyes();} };class?CommandNose:public?Command { public:CommandNose(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatNose();} };class?Nurse { public:Nurse(Command?*cmd){this->cmd?=??cmd;}~Nurse(){if(this->cmd?!=?NULL){delete?this->cmd;this->cmd?=?NULL;}}void?notify(){this->cmd->treat();} private:Command?*cmd; };int?main(void) {Nurse?*nurse?=?new?Nurse(new?CommandEyes(new?Doctor));nurse->notify();Nurse?*nurse2?=?new?Nurse(new?CommandNose(new?Doctor));nurse2->notify();return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? treat?eyes? treat?nose chunli@linux:~$把病單全部給護士長,讓護士長下發
chunli@linux:~$?cat?main.cpp? #include?<iostream> #include?<list> using?namespace?std; class?Doctor { public:void?treatEyes(){cout?<<"treat?eyes?"?<<?endl;}void?treatNose(){cout?<<"treat?nose"?<<?endl;} };class?Command { public:Command(Doctor?*doctor){this->doctor?=?doctor;}virtual?~Command(){if(this->doctor?!=?NULL){delete?this->doctor;this->doctor?=?NULL;}}virtual?void?treat()?=?0; protected:Doctor?*doctor; };class?CommandEyes:public?Command { public:CommandEyes(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatEyes();} };class?CommandNose:public?Command { public:CommandNose(Doctor*?doctor):Command(doctor){}void?treat(){this->doctor->treatNose();} };class?Nurse { public:Nurse(Command?*cmd){this->cmd?=??cmd;}~Nurse(){if(this->cmd?!=?NULL){delete?this->cmd;this->cmd?=?NULL;}}void?notify(){this->cmd->treat();} private:Command?*cmd; };class?NurseBoss { public:NurseBoss(){m_list.clear();}~NurseBoss(){m_list.clear();}void?setCmd(Command?*cmd){m_list.push_back(cmd);}void?notify(){for(list<Command*>::iterator?it?=?m_list.begin();it!=m_list.end();it++){(*it)->treat();}} private:list<Command*>?m_list; };int?main(void) {NurseBoss?*woman?=?new?NurseBoss;Command?*cmd1?=?new?CommandEyes(new?Doctor);Command?*cmd2?=?new?CommandNose(new?Doctor);woman->setCmd(cmd1);woman->setCmd(cmd2);woman->notify();return?0; } chunli@linux:~$?g++?main.cpp?-Wall??&&?./a.out? treat?eyes? treat?nose chunli@linux:~$命令模式,路邊吃烤串案例
chunli@linux:~$?cat?main.cpp? #include?<iostream> #include?<list> using?namespace?std;class?Cooker { public:void?makeChuaner(){cout?<<?"正在烤串?"?<<?endl;}void?makeChicken(){cout?<<?"正在烤雞翅?"?<<?endl;} };class?Command { public:Command(Cooker?*?cooker){this->cooker?=?cooker;}virtual?~Command(){if(this->cooker?!=?NULL){delete?this->cooker;this->cooker?=?NULL;}}virtual?void?execute()?=?0; protected:Cooker?*?cooker; };class?CommandChuaner:public?Command { public:CommandChuaner(Cooker?*?cooker):Command(cooker){}virtual?void?execute(){this->cooker->makeChuaner();} }; class?CommandChicken:public?Command { public:CommandChicken(Cooker?*?cooker):Command(cooker){}virtual?void?execute(){this->cooker->makeChicken();} };class?Waitress { public:Waitress(){this->m_list.clear();}~Waitress(){this->m_list.clear();}void?setCmd(Command?*cmd){this->m_list.push_back(cmd);}void?notify(){list<Command*>::iterator?it?=?m_list.begin();for(;it?!=?m_list.end();it++){(*it)->execute();//在此發生了多態}} private:list<Command*>?m_list; };int?main(void) {Waitress?*mm?=?new?Waitress; //喊一個服務器Command?*chuaner?=?new?CommandChuaner(new?Cooker);//點菜單Command?*chicken?=?new?CommandChicken(new?Cooker);//點菜單mm->setCmd(chuaner);//服務員登記mm->setCmd(chicken);mm->notify(); //服務員端菜return?0; } chunli@linux:~$?g++?main.cpp?-Wall??&&?./a.out? 正在烤串? 正在烤雞翅? chunli@linux:~$命令模式中的角色和職責 [圖]
? ?Command(抽象命令類): 抽象命令類一般是一個抽象類或接口,在
其中聲明了用于執行請求的execute()等方法,通過這些方法可以調用請求接收
者的相關操作。?
? ? ? ConcreteCommand(具體命令類):具體命令類是抽象命令類的子
類,實現了在抽象命令類中聲明的方法,它對應具體的接收者對象,將接收者
對象的動作綁定其中。在實現execute()方法時,將調用接收者對象的相關操作
(Action)。?
? Invoker(調用者): 調用者即請求發送者,它通過命令對象來執行請
求。一個調用者并不需要在設計時確定其接收者,因此它只與抽象命令類之間
存在關聯關系。在程序運行時可以將一個具體命令對象注入其中,再調用具體
命令對象的execute()方法,從而實現間接調用請求接收者的相關操作。?
? Receiver(接收者): 接收者執行與請求相關的操作,它具體實現對請
求的業務處理。?
5.2.3 命令模式的優缺點?
優點:?
? ? ? ?(1) 降低系統的耦合度。由于請求者與接收者之間不存在直接引用,因此請
求者與接收者之間實現完全解耦,相同的請求者可以對應不同的接收者,同樣,
相同的接收者也可以供不同的請求者使用,兩者之間具有良好的獨立性。?
? ? ? ?(2) 新的命令可以很容易地加入到系統中。由于增加新的具體命令類不會影
響到其他類,因此增加新的具體命令類很容易,無須修改原有系統源代碼,甚
至客戶類代碼,滿足“開閉原則”的要求。?
? ? ? ?(3) 可以比較容易地設計一個命令隊列或宏命令(組合命令)。?
缺點:?
? ? ? ? 使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個
對請求接收者的調用操作都需要設計一個具體命令類,因此在某些系統中可能
需要提供大量的具體命令類,這將影響命令模式的使用。?
5.2.4 適用場景?
? (1) 系統需要將請求調用者和請求接收者解耦,使得調用者和接收者不直
接交互。請求調用者無須知道接收者的存在,也無須知道接收者是誰,接收者
也無須關心何時被調用。?
? ? ? ? (2) 系統需要在不同的時間指定請求、將請求排隊和執行請求。一個命令
對象和請求的初始調用者可以有不同的生命期,換言之,最初的請求發出者可
能已經不在了,而命令對象本身仍然是活動的,可以通過該命令對象去調用請
求接收者,而無須關心請求調用者的存在性,可以通過請求日志文件等機制來
具體實現。?
? ? ? ?(3) 系統需要將一組操作組合在一起形成宏命令。?
? ? ? ?
? ? ? ?
===========================================
策略模式,英雄更換裝備戰斗場景
策略模式,不同時間不同的銷售模式
chunli@linux:~$?cat?main.cpp? #include?<iostream> using?namespace?std; class?AbstractStrategy { public:virtual?double?getPrice(double?price)?=?0; };class?StrategyA:public?AbstractStrategy//8折策略 { public:virtual?double?getPrice(double?price){return?price*0.8;} };class?StrategyB:public?AbstractStrategy?//滿200減100策略 { public:virtual?double?getPrice(double?price){if(price?>?200){price?-=?100;}return?price;} };class?Item { public:Item(string?name,double?price){this->name?=?name;this->price?=?price;}double?SellPrice(){return?this->strategy->getPrice(this->price);}void?setStrategy(AbstractStrategy?*?strategy){this->strategy?=?strategy;} private:string?name;double?price;AbstractStrategy?*?strategy; }; int?main(void) {Item?it("nike鞋",201);AbstractStrategy??*sa?=?new?StrategyA;AbstractStrategy??*sb?=?new?StrategyB;cout?<<?"上午,全場8折"?<<?endl;it.setStrategy(sa);cout?<<?"nike鞋應該賣"?<<it.SellPrice()?<<?endl;cout?<<?"下午,全場滿200減100"?<<?endl;it.setStrategy(sb);cout?<<?"nike鞋應該賣"?<<it.SellPrice()?<<?endl;return?0; } chunli@linux:~$?g++?main.cpp?-Wall??&&?./a.out? 上午,全場8折 nike鞋應該賣160.8 下午,全場滿200減100 nike鞋應該賣101 chunli@linux:~$策略模式中的角色和職責[圖]
? Context(環境類): 環境類是使用算法的角色,它在解決某個問題(即
實現某個方法)時可以采用多種策略。在環境類中維持一個對抽象策略類的引
用實例,用于定義所采用的策略。?
? Strategy(抽象策略類): 它為所支持的算法聲明了抽象方法,是所有
策略類的父類,它可以是抽象類或具體類,也可以是接口。環境類通過抽象策
略類中聲明的方法在運行時調用具體策略類中實現的算法。?
? ConcreteStrategy(具體策略類):它實現了在抽象策略類中聲明的算
法,在運行時,具體策略類將覆蓋在環境類中定義的抽象策略類對象,使用一
種具體的算法實現某個業務處理。?
5.3.3 策略模式的優缺點?
優點:?
? ? ? (1) 策略模式提供了對“開閉原則”的完美支持, 用戶可以在不修改原有系
統的基礎上選擇算法或行為,也可以靈活地增加新的算法或行為。?
? ? ? (2) ?使用策略模式可以避免多重條件選擇語句。多重條件選擇語句不易維護,
它把采取哪一種算法或行為的邏輯與算法或行為本身的實現邏輯混合在一起,
將它們全部硬編碼(Hard Coding)在一個龐大的多重條件選擇語句中,比直接繼
承環境類的辦法還要原始和落后。?
? ? ? (3) ?策略模式提供了一種算法的復用機制。由于將算法單獨提取出來封裝在
策略類中,因此不同的環境類可以方便地復用這些策略類。?
缺點:?
? ? ? (1) ?客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意
味著客戶端必須理解這些算法的區別,以便適時選擇恰當的算法。換言之,策
略模式只適用于客戶端知道所有的算法或行為的情況。?
? ? ? (2) ?策略模式將造成系統產生很多具體策略類,任何細小的變化都將導致系
統要增加一個新的具體策略類。?
5.3.4 適用場景?
? 準備一組算法,并將每一個算法封裝起來,使得它們可以互換。 ?
=========================================
觀察者模式,班長給學生放風,學生抄作業
觀察者模式,武林高手對決場景
chunli@linux:~$?cat?main.cpp? #include?<iostream> #include?<string> #include?<list> using?namespace?std;//前置聲明notifier class?Notifier;//抽象的觀察者 class?Linstenner { public://當朋友被揍了我改怎么辦virtual?void?onFriendBeFight(Linstenner?*one,?Linstenner?*another/*,?Notifier?*baixiao*/)?=?0;//one是打別人的人,?another?是被揍的virtual?void?fighting(Linstenner?*another,?Notifier?*notifier)?=?0;virtual?string?getName()?=?0;virtual?string?getParty()?=?0; };//抽象的通知者 class?Notifier { public://添加觀察者virtual?void?addListenner(Linstenner?*listenner)?=?0;//刪除觀察者virtual?void?delListenner(Linstenner?*listenner)?=?0;//通知觀察者virtual?void?notify(Linstenner?*one,?Linstenner?*another)?=?0; };//?武林中的人物 class?Hero?:public?Linstenner { public:Hero(string?name,?string?party){this->name?=?name;this->party?=?party;}//當我發現一個消息之后我該怎么辦virtual?void?onFriendBeFight(Linstenner?*one,?Linstenner?*another/*,?Notifier?*baixiao*/){if?(another->getName()?!=?this->name?&&one->getName()?!=?this->name)?{//不是當事人//如果不是當事人,需要判斷打人的pary?和?被打的party是不是我自己哥們if?(one->getParty()?==?this->party)?{//自己人把?比人揍了cout?<<?name?<<?"發現自己人把別人揍了,?笑了?,?拍手叫好"?<<?endl;}else?if?(another->getParty()?==?this->party){//自己人被揍了cout?<<?name?<<?"發現自己人被別人走了,?出手援救"?<<?endl;//this->fighting(one,?baixiao);}}else?{//當事人//如果是當事人,什么都不敢}}//揍人的方法virtual?void?fighting(Linstenner?*another,?Notifier?*notifier){cout?<<?name?<<?"["?<<?this->party?<<?"]"?<<?"?把?"?<<?another->getName()?<<?"["?<<?another->getParty()?<<?"]"?<<?"給揍了"?<<?endl;//?揍完之后,這個事件應該讓百曉生知曉//應該調用百曉生?的notify方法notifier->notify(this,?another);}string?getName()?{return?this->name;}string?getParty()?{return?this->party;}private:string?name;string?party; };class?Baixiao?:public?Notifier { public://添加觀察者virtual?void?addListenner(Linstenner?*listenner)??{this->l_list.push_back(listenner);}//刪除觀察者virtual?void?delListenner(Linstenner?*listenner)?{this->l_list.remove(listenner);}//通知觀察者virtual?void?notify(Linstenner?*one,?Linstenner?*another)??{for?(list<Linstenner?*>::iterator?it?=?l_list.begin();?it?!=?l_list.end();?it++)?{(*it)->onFriendBeFight(one,?another/*,?this*/);}} private://擁有所有武林人士的名單list<Linstenner*>?l_list; };int?main(void) {Linstenner?*hong7?=?new?Hero("洪七公",?"丐幫");Linstenner?*huangrong?=?new?Hero("黃蓉",?"丐幫");Linstenner?*wuyazi?=?new?Hero("無崖子",?"逍遙派");Linstenner?*tonglao?=?new?Hero("天山童姥",?"逍遙派");//創建一個百曉生Notifier?*baixiao?=?new?Baixiao;//百曉生?手機全部的武林人士名單baixiao->addListenner(hong7);baixiao->addListenner(huangrong);baixiao->addListenner(wuyazi);baixiao->addListenner(tonglao);//以上初始化完畢hong7->fighting(wuyazi,?baixiao);cout?<<?"----"?<<?endl;tonglao->fighting(hong7,?baixiao);return?0; } chunli@linux:~$?g++?main.cpp??&&?./a.out? 洪七公[丐幫]?把?無崖子[逍遙派]給揍了 黃蓉發現自己人把別人揍了,?笑了?,?拍手叫好 天山童姥發現自己人被別人走了,?出手援救 ---- 天山童姥[逍遙派]?把?洪七公[丐幫]給揍了 黃蓉發現自己人被別人走了,?出手援救 無崖子發現自己人把別人揍了,?笑了?,?拍手叫好 chunli@linux:~$觀察者模式中的角色和職責 [圖]
Subject(被觀察者或目標,抽象主題):被觀察的對象。當需要被觀察的狀
態發生變化時,需要通知隊列中所有觀察者對象。Subject需要維持(添加,
刪除,通知)一個觀察者對象的隊列列表。?
ConcreteSubject(具體被觀察者或目標,具體主題): 被觀察者的具體實
現。包含一些基本的屬性狀態及其他操作。?
Observer(觀察者):接口或抽象類。當Subject的狀態發生變化時,
Observer對象將通過一個callback函數得到通知。?
ConcreteObserver(具體觀察者):觀察者的具體實現。得到通知后將完成
一些具體的業務邏輯處理。?
5.4.3 觀察者模式的優缺點?
優點:?
? ? ? (1) 觀察者模式可以實現表示層和數據邏輯層的分離,定義了穩定的消息更
新傳遞機制,并抽象了更新接口,使得可以有各種各樣不同的表示層充當具體
觀察者角色。?
? ? ? (2) 觀察者模式在觀察目標和觀察者之間建立一個抽象的耦合。觀察目標只
需要維持一個抽象觀察者的集合,無須了解其具體觀察者。由于觀察目標和觀
察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。?
? ? ? (3) ?觀察者模式支持廣播通信,觀察目標會向所有已注冊的觀察者對象發送
通知,簡化了一對多系統設計的難度。?
? ? ? (4) 觀察者模式滿足“開閉原則”的要求,增加新的具體觀察者無須修改原
有系統代碼,在具體觀察者與觀察目標之間不存在關聯關系的情況下,增加新
的觀察目標也很方便。?
缺點:?
? ? ? (1) 如果一個觀察目標對象有很多直接和間接觀察者,將所有的觀察者都通
知到會花費很多時間。?
? ? ? (2) ?如果在觀察者和觀察目標之間存在循環依賴,觀察目標會觸發它們之間
進行循環調用,可能導致系統崩潰。?
? ? ? (3) 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生
變化的,而僅僅只是知道觀察目標發生了變化。?
5.4.4 適用場景?
? ?(1) 一個抽象模型有兩個方面,其中一個方面依賴于另一個方面,將這兩
個方面封裝在獨立的對象中使它們可以各自獨立地改變和復用。?
? ? ? ?(2) 一個對象的改變將導致一個或多個其他對象也發生改變,而并不知道
具體有多少對象將發生改變,也不知道這些對象是誰。?
? ? ? ? (3) 需要在系統中創建一個觸發鏈,A對象的行為將影響B對象,B對象的
行為將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。?
轉載于:https://blog.51cto.com/990487026/1877871
總結
以上是生活随笔為你收集整理的设计模式5 行为模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery总结06-动画事件02-上卷
- 下一篇: KVO本质