设计模式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 void useWeapon() = 0;
};
class KnifeStrategy:public AbstractStrategy
{
public:virtual void useWeapon(){cout << "使用 ××× " << endl;}
};
class AKStrategy:public AbstractStrategy
{
public:virtual void useWeapon(){cout << "使用 AK47 " << endl;}
};class Hero
{
public:Hero(){strategy = NULL; }void setStrategy(AbstractStrategy * strategy){ this->strategy = strategy;}void fight(){cout << "英雄开始战斗" << endl;this->strategy->useWeapon();}private:AbstractStrategy *strategy;};int main(void)
{AbstractStrategy * knife = new KnifeStrategy;AbstractStrategy * ak47  = new AKStrategy;Hero  *hero = new Hero ;cout << "---------------兵快来了,换AK47------------" << endl;hero->setStrategy(ak47);hero->fight();cout << "---------------近距离搏斗,换AK47------------" << endl;hero->setStrategy(knife);hero->fight();return 0;
}
chunli@linux:~$ g++ main.cpp -Wall  && ./a.out
---------------兵快来了,换AK47------------
英雄开始战斗
使用 AK47
---------------近距离搏斗,换AK47------------
英雄开始战斗
使用 ×××
chunli@linux:~$


策略模式,不同时间不同的销售模式


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 <list>
using namespace std;//------------------------------------------
//抽象层的观察者
class Listener//学生
{
public:virtual void DoSomething() = 0;//该干的virtual void DoOtherthing() = 0;//不该干的
};//抽象的被观察者
class Notify//班长
{
public:virtual void addlistener(Listener *listener) = 0;//添加学生   virtual void dellistener(Listener *listener) = 0;//删除学生virtual void notify() = 0;           //通知学生
};
//--------------------------------------------
class Student:public Listener//学生
{
public:Student(string name,string badthing){this->name = name;this->badthing = badthing;}virtual void DoSomething(){cout << "学生" <<name << "停止"<< badthing << ",改为写作业 " << endl;}virtual void DoOtherthing(){cout << "学生" <<name << "目前正在"<< badthing << endl;}
private:string name;string badthing;
};class Monitor:public Notify
{
public:virtual void addlistener(Listener *listener){this->m_list.push_back(listener);}     virtual void dellistener(Listener *listener){this->m_list.remove(listener);}virtual void notify(){list<Listener*>::iterator it = m_list.begin();for(;it!= m_list.end();it++){(*it)->DoSomething();}}
private:list<Listener*> m_list;   };int main(void)
{Listener *s1 = new Student("吴用","智取生辰纲");Listener *s2 = new Student("杨志","买刀");Listener *s3 = new Student("武松","醉打蒋门神");Notify *master = new Monitor;master->addlistener(s1);master->addlistener(s2);master->addlistener(s3);cout << "----老师没有来,大家可以抄作业" << endl;s1->DoOtherthing();s2->DoOtherthing();s3->DoOtherthing();cout << "----老师来了,大家该干啥干啥" << endl;master->notify();return 0;
}
chunli@linux:~$
chunli@linux:~$ g++ main.cpp -Wall  && ./a.out
----老师没有来,大家可以抄作业
学生吴用目前正在智取生辰纲
学生杨志目前正在买刀
学生武松目前正在醉打蒋门神
----老师来了,大家该干啥干啥
学生吴用停止智取生辰纲,改为写作业
学生杨志停止买刀,改为写作业
学生武松停止醉打蒋门神,改为写作业
chunli@linux:~$

观察者模式,武林高手对决场景


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 行为模式相关推荐

  1. java备忘录模式应用场景_图解Java设计模式之备忘录模式

    图解Java设计模式之备忘录模式 游戏角色状态恢复问题 游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态. ...

  2. 一看就懂!【英雄联盟锐雯】与 Python 详解设计模式之门面模式

    [网络配图] 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结.使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性.设计 ...

  3. Python设计模式-装饰器模式

    Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...

  4. Python设计模式-中介者模式

    Python设计模式-中介者模式 代码基于3.5.2,代码如下; #coding:utf-8 #中介者模式class colleague():mediator = Nonedef __init__(s ...

  5. Python设计模式-职责链模式

    Python设计模式-职责链模式 代码基于3.5.2,代码如下; #coding:utf-8 #职责链模式class Handler():def __init__(self):self.success ...

  6. Python设计模式-享元模式

    Python设计模式-享元模式 基于Python3.5.2,代码如下 #coding:utf-8class Coffee:name = ""price = 0def __init_ ...

  7. 建造者模式java_java设计模式3——建造者模式

    java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...

  8. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  9. 设计模式 | 工厂方法模式及典型应用

    工厂方法模式 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化.工厂方法模式让一个类的实例化延迟到其子类. 工厂方法模式又简称为工厂 ...

  10. [Head First设计模式]山西面馆中的设计模式——装饰者模式

    原文:[Head First设计模式]山西面馆中的设计模式--装饰者模式 引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里 ...

最新文章

  1. 部分人说 Java 的性能已经达到甚至超过 C++,是真的吗?
  2. 用SQL命令查看Mysql数据库大小
  3. 十张图解释机器学习的基本概念
  4. 自己动手制作笔记本SP2系统安装光盘
  5. 模仿Retrofit封装一个使用更简单的网络请求框架
  6. 【bzoj1026】[SCOI2009]windy数 数位dp
  7. wxWidgets:多重继承
  8. NYOJ--1236--挑战密室(第八届河南省程序设计大赛)
  9. 在IDEA连接MySql数据库时报错: [08001] CLIENT_PLUGIN_AUTH is required com.mysql.cj.exceptions.
  10. 理解Flexbox弹性盒子
  11. SharePoint Framework 构建你的第一个web部件(三)
  12. EBS业务学习之应付INVOICE类型
  13. JS每日一题:vue中keepalive怎么理解?
  14. Java连接sap无明显报错信息,Kettle连接SAP报错问题
  15. 麻省理工18年春软件构造课程阅读15“相等”
  16. 数学之路-数据分析进阶-转化率
  17. 常见的股票量化策略有哪些?
  18. C++ builder 遍历所有组件的 caption 属性,轻松实现界面多语言支持
  19. [填坑]ubuntu 18.04+Windows 10双硬盘双系统修改默认启动顺序
  20. 判断web网站是否站库分离

热门文章

  1. uva11990 动态逆序对
  2. Struts2.0实现的文件上传(单附件和多附件)以及附件下载功能
  3. php命名空间 动态 new,PHP命名空间(namespace)的动态访问及使用技巧_php实例
  4. LA3415保守的老师
  5. COSMIC功能规模度量方法
  6. 【Android 逆向】frida 框架安装 ( 设置 Python 3.7 版本 | 安装 frida 12.7.5 版本 | 安装 frida-tools 5.1.0 版本 )
  7. 【Java 并发编程】线程池机制 ( 线程池状态分析 | 线程池状态转换 | RUNNING | SHUTDOWN | STOP | TIDYING | TERMINATED )
  8. 【Android 安全】DEX 加密 ( Application 替换 | 分析 ContentProvider 组件中调用 getApplication() 获取的 Application 二 )
  9. 【运筹学】运输规划 ( 运输规划问题模型及变化 | 表上作业法引入 )
  10. 【DBMS 数据库管理系统】数据仓库中 数据追加 ( 时标方法 | DELTA 文件法 | 前后映像文件法 | 日志文件法 )