溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

設(shè)計模式5 行為模式

發(fā)布時間:2020-07-27 13:20:00 來源:網(wǎng)絡(luò) 閱讀:323 作者:990487026 欄目:移動開發(fā)

設(shè)計模式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;

	//鉤子函數(shù), hook
	virtual bool CustomWantAddThings() {
		return true;
	}


	//業(yè)務(wù)的邏輯的統(tǒng)一模板 
	void make() {
		boil();
		brew(); //子類
		putInCup(); 

		if (CustomWantAddThings() == true) {
			addThings(); //子類的多態(tài)
		}
	}
};

//制作咖啡
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:~$


模板方法模式中的角色和職責(zé) 

設(shè)計模式5 行為模式

  AbstractClass(抽象類):在抽象類中定義了一系列基本操作

(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一

個基本操作對應(yīng)算法的一個步驟,在其子類中可以重定義或?qū)崿F(xiàn)這些步驟。同

時,在抽象類中實現(xiàn)了一個模板方法(Template Method),用于定義一個算法

的框架,模板方法不僅可以調(diào)用在抽象類中實現(xiàn)的基本方法,也可以調(diào)用在抽

象類的子類中實現(xiàn)的基本方法,還可以調(diào)用其他對象中的方法。 

       ConcreteClass(具體子類): 它是抽象類的子類,用于實現(xiàn)在父類中聲

明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經(jīng)實現(xiàn)

的具體基本操作。 


模板方法的優(yōu)缺點 

優(yōu)點: 

       (1) 在父類中形式化地定義一個算法,而由它的子類來實現(xiàn)細(xì)節(jié)的處理,在

子類實現(xiàn)詳細(xì)的處理算法時并不會改變算法中步驟的執(zhí)行次序。 

       (2) 模板方法模式是一種代碼復(fù)用技術(shù),它在類庫設(shè)計中尤為重要,它提取

了類庫中的公共行為,將公共行為放在父類中,而通過其子類來實現(xiàn)不同的行

為,它鼓勵我們恰當(dāng)使用繼承來實現(xiàn)代碼復(fù)用。 

       (3) 可實現(xiàn)一種反向控制結(jié)構(gòu),通過子類覆蓋父類的鉤子方法來決定某一特

定步驟是否需要執(zhí)行。 

       (4) 在模板方法模式中可以通過子類來覆蓋父類的基本方法,不同的子類可

以提供基本方法的不同實現(xiàn),更換和增加新的子類很方便,符合單一職責(zé)原則

和開閉原則。 

  

缺點: 

       需要為每一個基本方法的不同實現(xiàn)提供一個子類,如果父類中可變的基本

方法太多,將會導(dǎo)致類的個數(shù)增加,系統(tǒng)更加龐大,設(shè)計也更加抽象。


適用場景 

  (1)具有統(tǒng)一的操作步驟或操作過程; 

 (2) 具有不同的操作細(xì)節(jié); 

 (3) 存在多個具有同樣操作步驟的應(yīng)用場景,但某些具體的操作細(xì)節(jié)卻各


不相同; 

   在抽象類中統(tǒng)一操作步驟,并規(guī)定好接口;讓子類實現(xiàn)接口。這樣

可以把各個具體的子類和操作步驟解耦合。 


命令模式:病人看病直接找醫(yī)生,耦合度太高.

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:~$




拿著病單來看醫(yī)生,醫(yī)生只跟病單打交道

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)
{
	//拿著病單來看醫(yī)生
	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:~$




讓護(hù)士接病單,通知病人來看病:

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:~$



把病單全部給護(hù)士長,讓護(hù)士長下發(fā)

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();//在此發(fā)生了多態(tài)
		}
	}
private:
	list<Command*> m_list;
};

int main(void)
{
	Waitress *mm = new Waitress;	//喊一個服務(wù)器
	Command *chuaner = new CommandChuaner(new Cooker);//點菜單
	Command *chicken = new CommandChicken(new Cooker);//點菜單
	mm->setCmd(chuaner);//服務(wù)員登記
	mm->setCmd(chicken);
	mm->notify();	//服務(wù)員端菜
	
	return 0;
}
chunli@linux:~$ g++ main.cpp -Wall  && ./a.out 
正在烤串 
正在烤雞翅 
chunli@linux:~$



命令模式中的角色和職責(zé) [圖]

設(shè)計模式5 行為模式



   Command(抽象命令類): 抽象命令類一般是一個抽象類或接口,在

其中聲明了用于執(zhí)行請求的execute()等方法,通過這些方法可以調(diào)用請求接收

者的相關(guān)操作。 

      ConcreteCommand(具體命令類):具體命令類是抽象命令類的子

類,實現(xiàn)了在抽象命令類中聲明的方法,它對應(yīng)具體的接收者對象,將接收者

對象的動作綁定其中。在實現(xiàn)execute()方法時,將調(diào)用接收者對象的相關(guān)操作

(Action)。 

  Invoker(調(diào)用者): 調(diào)用者即請求發(fā)送者,它通過命令對象來執(zhí)行請

求。一個調(diào)用者并不需要在設(shè)計時確定其接收者,因此它只與抽象命令類之間

存在關(guān)聯(lián)關(guān)系。在程序運行時可以將一個具體命令對象注入其中,再調(diào)用具體

命令對象的execute()方法,從而實現(xiàn)間接調(diào)用請求接收者的相關(guān)操作。 

  Receiver(接收者): 接收者執(zhí)行與請求相關(guān)的操作,它具體實現(xiàn)對請

求的業(yè)務(wù)處理。 



5.2.3 命令模式的優(yōu)缺點 

優(yōu)點: 

       (1) 降低系統(tǒng)的耦合度。由于請求者與接收者之間不存在直接引用,因此請

求者與接收者之間實現(xiàn)完全解耦,相同的請求者可以對應(yīng)不同的接收者,同樣,

相同的接收者也可以供不同的請求者使用,兩者之間具有良好的獨立性。 

       (2) 新的命令可以很容易地加入到系統(tǒng)中。由于增加新的具體命令類不會影

響到其他類,因此增加新的具體命令類很容易,無須修改原有系統(tǒng)源代碼,甚

至客戶類代碼,滿足“開閉原則”的要求。 

       (3) 可以比較容易地設(shè)計一個命令隊列或宏命令(組合命令)。 

缺點: 

        使用命令模式可能會導(dǎo)致某些系統(tǒng)有過多的具體命令類。因為針對每一個

對請求接收者的調(diào)用操作都需要設(shè)計一個具體命令類,因此在某些系統(tǒng)中可能

需要提供大量的具體命令類,這將影響命令模式的使用。 



5.2.4 適用場景 

  (1) 系統(tǒng)需要將請求調(diào)用者和請求接收者解耦,使得調(diào)用者和接收者不直

接交互。請求調(diào)用者無須知道接收者的存在,也無須知道接收者是誰,接收者

也無須關(guān)心何時被調(diào)用。 

        (2) 系統(tǒng)需要在不同的時間指定請求、將請求排隊和執(zhí)行請求。一個命令

對象和請求的初始調(diào)用者可以有不同的生命期,換言之,最初的請求發(fā)出者可

能已經(jīng)不在了,而命令對象本身仍然是活動的,可以通過該命令對象去調(diào)用請

求接收者,而無須關(guān)心請求調(diào)用者的存在性,可以通過請求日志文件等機(jī)制來

具體實現(xiàn)。 

       (3) 系統(tǒng)需要將一組操作組合在一起形成宏命令。 

       

       




===========================================



策略模式,英雄更換裝備戰(zhàn)斗場景


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 << "英雄開始戰(zhàn)斗" << 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------------
英雄開始戰(zhàn)斗
使用 AK47 
---------------近距離搏斗,換AK47------------
英雄開始戰(zhàn)斗
使用 ××× 
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鞋應(yīng)該賣" <<it.SellPrice() << endl;
	
		
	cout << "下午,全場滿200減100" << endl;
	it.setStrategy(sb);
	cout << "nike鞋應(yīng)該賣" <<it.SellPrice() << endl;



	return 0;
}
chunli@linux:~$ g++ main.cpp -Wall  && ./a.out 
上午,全場8折
nike鞋應(yīng)該賣160.8
下午,全場滿200減100
nike鞋應(yīng)該賣101
chunli@linux:~$


策略模式中的角色和職責(zé)[圖]

設(shè)計模式5 行為模式


  Context(環(huán)境類): 環(huán)境類是使用算法的角色,它在解決某個問題(即

實現(xiàn)某個方法)時可以采用多種策略。在環(huán)境類中維持一個對抽象策略類的引

用實例,用于定義所采用的策略。 

  Strategy(抽象策略類): 它為所支持的算法聲明了抽象方法,是所有

策略類的父類,它可以是抽象類或具體類,也可以是接口。環(huán)境類通過抽象策

略類中聲明的方法在運行時調(diào)用具體策略類中實現(xiàn)的算法。 

  ConcreteStrategy(具體策略類):它實現(xiàn)了在抽象策略類中聲明的算

法,在運行時,具體策略類將覆蓋在環(huán)境類中定義的抽象策略類對象,使用一

種具體的算法實現(xiàn)某個業(yè)務(wù)處理。 



5.3.3 策略模式的優(yōu)缺點 

優(yōu)點: 

      (1) 策略模式提供了對“開閉原則”的完美支持, 用戶可以在不修改原有系

統(tǒng)的基礎(chǔ)上選擇算法或行為,也可以靈活地增加新的算法或行為。 

      (2)  使用策略模式可以避免多重條件選擇語句。多重條件選擇語句不易維護(hù),

它把采取哪一種算法或行為的邏輯與算法或行為本身的實現(xiàn)邏輯混合在一起,

將它們?nèi)坑簿幋a(Hard Coding)在一個龐大的多重條件選擇語句中,比直接繼

承環(huán)境類的辦法還要原始和落后。 

      (3)  策略模式提供了一種算法的復(fù)用機(jī)制。由于將算法單獨提取出來封裝在

策略類中,因此不同的環(huán)境類可以方便地復(fù)用這些策略類。 

缺點: 

      (1)  客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意

味著客戶端必須理解這些算法的區(qū)別,以便適時選擇恰當(dāng)?shù)乃惴?。換言之,策

略模式只適用于客戶端知道所有的算法或行為的情況。 

      (2)  策略模式將造成系統(tǒng)產(chǎn)生很多具體策略類,任何細(xì)小的變化都將導(dǎo)致系

統(tǒng)要增加一個新的具體策略類。 




5.3.4 適用場景 

  準(zhǔn)備一組算法,并將每一個算法封裝起來,使得它們可以互換。  




=========================================



觀察者模式,班長給學(xué)生放風(fēng),學(xué)生抄作業(yè)

chunli@linux:~$ cat main.cpp 
#include <iostream>
#include <list>
using namespace std;

//------------------------------------------
//抽象層的觀察者
class Listener//學(xué)生
{
public:
	virtual void DoSomething() = 0;//該干的
	virtual void DoOtherthing() = 0;//不該干的
};

//抽象的被觀察者
class Notify//班長
{
public:
	virtual void addlistener(Listener *listener) = 0;//添加學(xué)生	  
	virtual void dellistener(Listener *listener) = 0;//刪除學(xué)生
	virtual void notify() = 0;	  		//通知學(xué)生
};
//--------------------------------------------
class Student:public Listener//學(xué)生
{
public:
	Student(string name,string badthing)
	{
		this->name = name;
		this->badthing = badthing;
	}
	virtual void DoSomething()
	{
		cout << "學(xué)生" <<name << "停止"<< badthing << ",改為寫作業(yè) " << endl;
	}
	virtual void DoOtherthing()
	{
		cout << "學(xué)生" <<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 << "----老師沒有來,大家可以抄作業(yè)" << endl;
	s1->DoOtherthing();
	s2->DoOtherthing();
	s3->DoOtherthing();

	cout << "----老師來了,大家該干啥干啥" << endl;
	master->notify();
	


	return 0;
}
chunli@linux:~$ 
chunli@linux:~$ g++ main.cpp -Wall  && ./a.out 
----老師沒有來,大家可以抄作業(yè)
學(xué)生吳用目前正在智取生辰綱
學(xué)生楊志目前正在買刀
學(xué)生武松目前正在醉打蔣門神
----老師來了,大家該干啥干啥
學(xué)生吳用停止智取生辰綱,改為寫作業(yè) 
學(xué)生楊志停止買刀,改為寫作業(yè) 
學(xué)生武松停止醉打蔣門神,改為寫作業(yè) 
chunli@linux:~$


觀察者模式,武林高手對決場景

chunli@linux:~$ cat main.cpp 
#include <iostream>
#include <string>
#include <list>
using namespace std;


//前置聲明notifier
class Notifier;

//抽象的觀察者
class Linstenner
{
public:
	//當(dāng)朋友被揍了我改怎么辦
	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;
	}

	//當(dāng)我發(fā)現(xiàn)一個消息之后我該怎么辦
	virtual void onFriendBeFight(Linstenner *one, Linstenner *another/*, Notifier *baixiao*/)
	{
		if (another->getName() != this->name &&one->getName() != this->name) {
			//不是當(dāng)事人
			//如果不是當(dāng)事人,需要判斷打人的pary 和 被打的party是不是我自己哥們
			if (one->getParty() == this->party) {
				//自己人把 比人揍了
				cout << name << "發(fā)現(xiàn)自己人把別人揍了, 笑了 , 拍手叫好" << endl;
			}
			else if (another->getParty() == this->party){
				//自己人被揍了
				cout << name << "發(fā)現(xiàn)自己人被別人走了, 出手援救" << endl;
				//this->fighting(one, baixiao);
			}
		}
		else {
			//當(dāng)事人
			//如果是當(dāng)事人,什么都不敢

		}
	}

	//揍人的方法
	virtual void fighting(Linstenner *another, Notifier *notifier)
	{
		cout << name << "[" << this->party << "]" << " 把 " 
			<< another->getName() << "[" << another->getParty() << "]" << "給揍了" << endl;

      // 揍完之后,這個事件應(yīng)該讓百曉生知曉
		//應(yīng)該調(diào)用百曉生 的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("天山童姥", "逍遙派");

	//創(chuàng)建一個百曉生
	Notifier *baixiao = new Baixiao;

	//百曉生 手機(jī)全部的武林人士名單
	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 
洪七公[丐幫] 把 無崖子[逍遙派]給揍了
黃蓉發(fā)現(xiàn)自己人把別人揍了, 笑了 , 拍手叫好
天山童姥發(fā)現(xiàn)自己人被別人走了, 出手援救
----
天山童姥[逍遙派] 把 洪七公[丐幫]給揍了
黃蓉發(fā)現(xiàn)自己人被別人走了, 出手援救
無崖子發(fā)現(xiàn)自己人把別人揍了, 笑了 , 拍手叫好
chunli@linux:~$


觀察者模式中的角色和職責(zé) [圖]



Subject(被觀察者或目標(biāo),抽象主題):被觀察的對象。當(dāng)需要被觀察的狀

態(tài)發(fā)生變化時,需要通知隊列中所有觀察者對象。Subject需要維持(添加,

刪除,通知)一個觀察者對象的隊列列表。 

ConcreteSubject(具體被觀察者或目標(biāo),具體主題): 被觀察者的具體實

現(xiàn)。包含一些基本的屬性狀態(tài)及其他操作。 

Observer(觀察者):接口或抽象類。當(dāng)Subject的狀態(tài)發(fā)生變化時,

Observer對象將通過一個callback函數(shù)得到通知。 

ConcreteObserver(具體觀察者):觀察者的具體實現(xiàn)。得到通知后將完成

一些具體的業(yè)務(wù)邏輯處理。 



5.4.3 觀察者模式的優(yōu)缺點 

優(yōu)點: 

      (1) 觀察者模式可以實現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,定義了穩(wěn)定的消息更

新傳遞機(jī)制,并抽象了更新接口,使得可以有各種各樣不同的表示層充當(dāng)具體

觀察者角色。 

      (2) 觀察者模式在觀察目標(biāo)和觀察者之間建立一個抽象的耦合。觀察目標(biāo)只

需要維持一個抽象觀察者的集合,無須了解其具體觀察者。由于觀察目標(biāo)和觀

察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。 

      (3)  觀察者模式支持廣播通信,觀察目標(biāo)會向所有已注冊的觀察者對象發(fā)送

通知,簡化了一對多系統(tǒng)設(shè)計的難度。 

      (4) 觀察者模式滿足“開閉原則”的要求,增加新的具體觀察者無須修改原

有系統(tǒng)代碼,在具體觀察者與觀察目標(biāo)之間不存在關(guān)聯(lián)關(guān)系的情況下,增加新

的觀察目標(biāo)也很方便。 

缺點: 

      (1) 如果一個觀察目標(biāo)對象有很多直接和間接觀察者,將所有的觀察者都通

知到會花費很多時間。 

      (2)  如果在觀察者和觀察目標(biāo)之間存在循環(huán)依賴,觀察目標(biāo)會觸發(fā)它們之間

進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。 

      (3) 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對象是怎么發(fā)生

變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。 




5.4.4 適用場景 

   (1) 一個抽象模型有兩個方面,其中一個方面依賴于另一個方面,將這兩

個方面封裝在獨立的對象中使它們可以各自獨立地改變和復(fù)用。 

       (2) 一個對象的改變將導(dǎo)致一個或多個其他對象也發(fā)生改變,而并不知道

具體有多少對象將發(fā)生改變,也不知道這些對象是誰。 

        (3) 需要在系統(tǒng)中創(chuàng)建一個觸發(fā)鏈,A對象的行為將影響B(tài)對象,B對象的

行為將影響C對象……,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制。 




向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI