設計模式(3)---觀察者模式

觀察者模式

當對象存在一對多的關係時,則使用觀察者模式(Observer Pattern)。比如,當一個對象被修改時,則會自動通知它依賴對象。觀察者模式屬於行爲型模式,又被稱爲發佈-訂閱模式、模式-視圖模式、源-監聽器模式或從屬者模式。觀察者模式中分爲目標和觀察者,目標可以被多個觀察者所觀察,目標的狀態變化發生變化時,觀察該目標的所有觀察者將得到通知,通常被用作事件的實時處理。這種模式類似於電影上搖骰子的情況,這時那些賭徒就是觀察者,那個骰子就是目標,當骰盅被打開時會有一個人來讀點,用來通知給那些下注的賭徒,那些賭徒會根據骰子的點數作出相應的動作。

適用情景:

(1)C/S模式下的消息實時發佈。

(2)股票大盤的消息實時更新。

模式結構

觀察者模式中具體分爲:

(1)目標(subject):目標將所有觀察者對象保存在一個聚集(數組、鏈表)裏,每個目標都可以擁有任意數量的觀察者。目標提供一個接口,可以增加和刪除觀察者的對象,目標又被稱爲:抽象主題角色或被觀察者角色,一般使用一個抽象類或接口實現。

 (2)具體目標 (Concrete Subject):將有關狀態狀態存入具體觀察者對象;當具體目標的內部狀態改變時,給登記過的觀察者(觀察該目標的所有觀察者)發出通知。具體目標又被稱爲:具體主題角色或具體被觀察者角色,一般使用一個具體的子類實現。

(3) 觀察者 (observer):爲所有的具體觀察者定義一個接口,在得到目標的通知時更新自己。這個接口叫做更新接口。觀察者一般用一個抽象類或者一個接口實現。在抽像類中,更新接口只包含一個方法(updata方法),這個方法叫做更新方法。觀察者又被稱爲抽象觀察者角色。

 (4)具體觀察者(Concrete Observer):存儲與目標的狀態自恰的狀態。具體觀察者實現了觀察者的所有更新接口,以便使本身的狀態與目標狀態協調。如果需要,具體觀察者角色可以保存一個指向具體目標對象的引用或指針。具體觀察者又被稱爲具體觀察者角色,通常使用一個具體的子類實現。

其中,目標和觀察者屬於抽像類爲具體目標和具體觀察者提供接口。

觀察者模式的優點:

(1)觀察者模式在目標和觀察者之間建立了一個抽象的耦合。被觀察者角色所知道的只是一個具體的觀察者的聚集,每一個具體的觀察者都符合一個抽象觀察者的接口。目標並不認識任何一個具體的觀察者,它只知道它們都有一個共同的接口。由於目標和觀察者沒有緊密的耦合在一起,因此它們可以屬於不同的抽象化層次。

(2)觀察者模式支持廣播通信。目標會向所有的登記過的觀察者發出通知。

觀察者模式的缺點:

(1)如果一個目標有很多直接和間接的觀察者時,將所有的觀察者都通知到會花費很多時間。

(2)如果在目標和觀察者之間有循環依賴的化,目標會觸發它們的循環調用,導致程序崩潰。

(3)觀察無法知道目標時如何變化的,只能被動的接受變化的結果。

具體實現

#include <iostream>
#include <string>
#include <list>
using namespace std;
//觀察者
class Observer
{
public:
	Observer()
	{

	}
	virtual ~Observer()
	{

	}
	//負責更新目標的通知
	virtual void updata() = 0;
};
//目標
class Subject
{
public:
	Subject()
	{

	}
	virtual ~Subject()
	{

	}
	void addObserver(Observer* pObject); //添加觀察者
	void delObserver(Observer* pObject); //刪除觀察者
	void noticeAllObserver();            //通知觀察者
	virtual int getStatus() = 0;         //獲取目標狀態
	virtual void setStatus(int) = 0;     //設置目標狀態
private: 
	list<Observer*> observerList;         //用來保存觀察者的隊列
};

void Subject::addObserver(Observer* pObject)
{
	observerList.push_back(pObject);
}

void Subject::delObserver(Observer* pObject)
{
	list<Observer*>::iterator iter = observerList.begin();
	for (; iter != observerList.end(); ++iter)
	{
		if (*iter == pObject)
		{
			iter = observerList.erase(iter);
			break;
		}
	}
}

void Subject::noticeAllObserver()
{
	list<Observer*>::iterator iter = observerList.begin();
	for (; iter != observerList.end(); ++iter)
	{
		(*iter)->updata();
	}
}
//實際觀察者
class concreteObserver :public Observer
{
public:
	concreteObserver(string obName, Subject* subject)
		:observerName(obName), mySubject(subject)
	{

	}
	~concreteObserver()
	{

	}
	void updata()
	{
		cout << "updata:[myName:" << observerName << ",mySubjectStatus:" << mySubject->getStatus() << "]" << endl;
	}
private:
	string observerName;   //觀察者名稱
	Subject* mySubject;    //觀察者觀察的目標
};
//實際目標
class concreteSubject:public Subject
{
public:
	concreteSubject(string subName,int status)
		:subjectName(subName), subjectStatus(status)
	{
		cout << "subjectName:" << subjectName << ",subjectStatus:" << subjectStatus << endl;
	}
	int getStatus()
	{
		return subjectStatus;
	}
	void setStatus(int status)
	{
		subjectStatus = status;
		cout << "subjectName:" << subjectName << ",subjectStatus:" << subjectStatus << endl;
	}
private:
	string subjectName;   //目標名稱
	int subjectStatus;    //目標狀態
};

int main()
{
	concreteSubject *subjectA = new concreteSubject("目標A",1);
	concreteSubject *subjectB = new concreteSubject("目標B",2);
	concreteObserver *observer1 = new concreteObserver("1號觀察者", subjectA);
	subjectA->addObserver(observer1);
	concreteObserver *observer2 = new concreteObserver("2號觀察者", subjectA);
	subjectA->addObserver(observer2);
	concreteObserver *observer3 = new concreteObserver("3號觀察者", subjectB);
	subjectB->addObserver(observer3);
	concreteObserver *observer4 = new concreteObserver("4號觀察者", subjectB);
	subjectB->addObserver(observer4);
	subjectA->noticeAllObserver();
	subjectB->noticeAllObserver();
	//目標A,狀態 1:1號觀察者,2號觀察者
	//目標B,狀態 2:3號觀察者,4號觀察者
	cout << "-------------------修改目標A和目標B的狀態--------------------------" << endl;
	subjectA->setStatus(3);
	subjectB->setStatus(4);
	subjectA->noticeAllObserver();
	subjectB->noticeAllObserver();
	//目標A,狀態 3:1號觀察者,2號觀察者
	//目標B,狀態 4:3號觀察者,4號觀察者
	cout << "-------------------讓1、3觀察A,讓2、4觀察B--------------------------" << endl;
	subjectA->delObserver(observer2);
	subjectB->delObserver(observer3);
	subjectA->addObserver(observer3);
	subjectB->addObserver(observer2);
	subjectA->setStatus(5);
	subjectB->setStatus(6);
	subjectA->noticeAllObserver();
	subjectB->noticeAllObserver();
	//目標A,狀態 5:1號觀察者,3號觀察者
	//目標B,狀態 6:2號觀察者,4號觀察者
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章