設計模式之觀察者模式(c++)


Observer 模式應該可以說是應用最多、影響最廣的模式之一,因為 Observer 的一個實例 Model/View/Control( MVC) 結構在系統開發架構設計中有着很重要的地位和意義, MVC實現了業務邏輯和表示層的解耦。在 MFC 中, Doc/View(文檔視圖結構)提供了實現 MVC 的框架結構。在 Java 陣容中, Struts 則提供和 MFC 中 Doc/View 結構類似的實現 MVC 的框架。另外 Java 語言本身就提供了 Observer 模式的實現接口。當然, MVC 只是 Observer 模式的一個實例。 Observer 模式要解決的問題為: 建立一個一( Subject)對多( Observer) 的依賴關系, 並且做到當“一” 變化的時候, 依賴這個“一”的多也能夠同步改變。

在GOF的《設計模式:可復用面向對象軟件的基礎》一書中對觀察者模式是這樣說的:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。當一個對象發生了變化,關注它的對象就會得到通知;這種交互也稱為發布-訂閱(publish-subscribe)。目標是通知的發布者,它發出通知時並不需要知道誰是它的觀察者。

最常見的一個例子就是: 對同一組數據進行統計分析時候, 我們希望能夠提供多種形式的表示 (例如以表格進行統計顯示、柱狀圖統計顯示、百分比統計顯示等)。這些表示都依賴於同一組數據, 我們當然需要當數據改變的時候, 所有的統計的顯示都能夠同時改變。 Observer 模式就是解決了這一個問題。

UML類圖:

Subject(目標)
——目標知道它的觀察者。可以有任意多個觀察者觀察同一個目標;
——提供注冊和刪除觀察者對象的接口。

Observer(觀察者)
——為那些在目標發生改變時需獲得通知的對象定義一個更新接口。

ConcreteSubject(具體目標)
——將有關狀態存入各ConcreteObserver對象;
——當它的狀態發生改變時,向它的各個觀察者發出通知。

ConcreteObserver(具體觀察者)
——維護一個指向ConcreteSubject對象的引用;
——存儲有關狀態,這些狀態應與目標的狀態保持一致;
——實現Observer的更新接口以使自身狀態與目標的狀態保持一致。

觀察者模式按照以下方式進行協作:

    1. 當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者;
    2. 在得到一個具體目標的改變通知后,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。

以下是調用時序圖:

適用場合

在以下任一情況下都可以使用觀察者模式:

  1. 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立的改變和復用;
  2. 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變;
  3. 當一個對象必須通知其它對象,而它又不能假定其它對象是誰;也就是說,你不希望這些對象是緊密耦合的。

代碼實現:

#include <iostream>
#include <list>
using namespace std;

class Observer
{
public:
	virtual void Update(int) = 0;
};

class Subject
{
public:
	virtual void Attach(Observer *) = 0;
	virtual void Detach(Observer *) = 0;
	virtual void Notify() = 0;
};

class ConcreteObserver : public Observer
{
public:
	ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}

	void Update(int value)
	{
		cout << "ConcreteObserver get the update. New State:" << value << endl;
	}

private:
	Subject *m_pSubject;
};

class ConcreteObserver2 : public Observer
{
public:
	ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}

	void Update(int value)
	{
		cout << "ConcreteObserver2 get the update. New State:" << value << endl;
	}

private:
	Subject *m_pSubject;
};

class ConcreteSubject : public Subject
{
public:
	void Attach(Observer *pObserver);
	void Detach(Observer *pObserver);
	void Notify();

	void SetState(int state)
	{
		m_iState = state;
	}

private:
	std::list<Observer *> m_ObserverList;
	int m_iState;
};

void ConcreteSubject::Attach(Observer *pObserver)
{
	m_ObserverList.push_back(pObserver);
}

void ConcreteSubject::Detach(Observer *pObserver)
{
	m_ObserverList.remove(pObserver);
}

void ConcreteSubject::Notify()
{
	std::list<Observer *>::iterator it = m_ObserverList.begin();
	while (it != m_ObserverList.end())
	{
		(*it)->Update(m_iState);
		++it;
	}
}

int main()
{
	// Create Subject
	ConcreteSubject *pSubject = new ConcreteSubject();

	// Create Observer
	Observer *pObserver = new ConcreteObserver(pSubject);
	Observer *pObserver2 = new ConcreteObserver2(pSubject);

	// Change the state
	pSubject->SetState(2);

	// Register the observer
	pSubject->Attach(pObserver);
	pSubject->Attach(pObserver2);

	pSubject->Notify();

	// Unregister the observer
	pSubject->Detach(pObserver);

	pSubject->SetState(3);
	pSubject->Notify();

	delete pObserver;
	delete pObserver2;
	delete pSubject;
}

vs2013運行結果:

 

示例2代碼實現:  

 

這里的目標 Subject 提供依賴於它的觀察者 Observer 的注冊( Attach) 和注銷( Detach)操作,並且提供了使得依賴於它的所有觀察者同步的操作( Notify)。 觀察者 Observer 則提供一個 Update 操作, 注意這里的 Observer 的 Update 操作並不在 Observer 改變了 Subject 目標狀態的時候就對自己進行更新, 這個更新操作要延遲到 Subject 對象發出 Notify 通知所有Observer 進行修改(調用 Update)。

#include <iostream>
#include <string>
#include <list>
using namespace std;

class Subject;
//抽象觀察者
class Observer
{
protected:
	string name;
	Subject *sub;
public:
	Observer(string name, Subject *sub)
	{
		this->name = name;
		this->sub = sub;
	}
	virtual void update() = 0;
};
//具體的觀察者,看股票的
class StockObserver :public Observer
{
public:
	StockObserver(string name, Subject *sub) :Observer(name, sub)
	{
	}
	void update();
};
//具體的觀察者,看NBA的
class NBAObserver :public Observer
{
public:
	NBAObserver(string name, Subject *sub) :Observer(name, sub)
	{
	}
	void update();
};
//抽象通知者
class Subject
{
protected:
	list<Observer*> observers;
public:
	string action;
	virtual void attach(Observer*) = 0;
	virtual void detach(Observer*) = 0;
	virtual void notify() = 0;
};
//具體通知者,秘書
class Secretary :public Subject
{
	void attach(Observer *observer)
	{
		observers.push_back(observer);
	}
	void detach(Observer *observer)
	{
		list<Observer *>::iterator iter = observers.begin();
		while (iter != observers.end())
		{
			if ((*iter) == observer)
			{
				observers.erase(iter);
			}
			++iter;
		}
	}
	void notify()
	{
		list<Observer *>::iterator iter = observers.begin();
		while (iter != observers.end())
		{
			(*iter)->update();
			++iter;
		}
	}
};

void StockObserver::update()
{
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "梁所長來了!")
	{
		cout << "我馬上關閉股票,裝做很認真工作的樣子!" << endl;
	}
}

void NBAObserver::update()
{
	cout << name << " 收到消息:" << sub->action << endl;
	if (sub->action == "梁所長來了!")
	{
		cout << "我馬上關閉NBA,裝做很認真工作的樣子!" << endl;
	}
}

int main()
{
	Subject *dwq = new Secretary(); //創建觀察者
    //被觀察的對象 Observer *xs = new NBAObserver("xiaoshuai", dwq); Observer *zy = new NBAObserver("zouyue", dwq); Observer *lm = new StockObserver("limin", dwq);     //加入觀察隊列 dwq->attach(xs); dwq->attach(zy); dwq->attach(lm);     //事件 dwq->action = "去吃飯了!";
    //通知 dwq->notify(); cout << endl; dwq->action = "梁所長來了!"; dwq->notify(); return 0; }

運行結果:

 

  

參考文獻:

《大話設計模式 C++》

《C++設計模式》

C++設計模式——觀察者模式

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM