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的更新接口以使自身狀態與目標的狀態保持一致。
觀察者模式按照以下方式進行協作:
- 當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者;
- 在得到一個具體目標的改變通知后,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。
以下是調用時序圖:

適用場合
在以下任一情況下都可以使用觀察者模式:
- 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立的改變和復用;
- 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變;
- 當一個對象必須通知其它對象,而它又不能假定其它對象是誰;也就是說,你不希望這些對象是緊密耦合的。
代碼實現:
#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++設計模式》
