這篇會有點抽象,我搞了一下午。
從“狼來了”的故事說起
從前有一堆學生,下課偷偷打遊戲。但是他們的班主任卻總會在不該出現的時間,出現在不該出現的地點–教室後門。
這些學生實在忍無可忍了,他們想了一個辦法,買通了他們的班長,由班長爲他們放風,當然,誰要請班長放風,就得加入班長的放風小隊。一旦有任何風吹草動,班長就會立刻通知他們。
從此,他們過上了無憂無慮的生活,從此,他們與大學失之交臂。
故事中有那些元素呢?有放風的班長、請班長放風的學生、班長的通知名單、班長的通知狀態、學生的應對狀態,當然,特別重要的還有他們的班主任。
這些元素,便構成了今天這篇”觀察者模式“的主題。
觀察者模式
Observer 模式應該可以說是應用最多、影響最廣的模式之一,因爲 Observer 的一個實例 Model/View/Control( MVC) 結構在系統開發架構設計中有着很重要的地位和意義, MVC實現了業務邏輯和表示層的解耦。
在GOF的《設計模式:可複用面向對象軟件的基礎》一書中對觀察者模式是這樣說的:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。當一個對象發生了變化,關注它的對象就會得到通知;這種交互也稱爲發佈-訂閱(publish-subscribe)。目標是通知的發佈者,它發出通知時並不需要知道誰是它的觀察者。
如果對Linux編程有一定基礎的朋友,肯定知道條件變量吧,條件變量的廣播,就是典型的觀察者模型。
UML類圖
Subject(目標)(就是班長)
——目標知道它的觀察者。可以有任意多個觀察者觀察同一個目標;
——提供註冊和刪除觀察者對象的接口。
Observer(觀察者)(就是學生)
——爲那些在目標發生改變時需獲得通知的對象定義一個更新接口。
ConcreteSubject(具體目標)
——將有關狀態存入各ConcreteObserver對象;
——當它的狀態發生改變時,向它的各個觀察者發出通知。
ConcreteObserver(具體觀察者)
——維護一個指向ConcreteSubject對象的引用;
——存儲有關狀態,這些狀態應與目標的狀態保持一致;
——實現Observer的更新接口以使自身狀態與目標的狀態保持一致。
當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者;
在得到一個具體目標的改變通知後,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。
故事轉代碼
#include<iostream>
#include<vector>
using namespace std;
class abstractstudent {//抽象觀察者
public:
virtual void update(int) = 0; //實時更新動態
};
class abstractmonitor {//抽象監聽者
public:
//業務配置
virtual void addStudent(abstractstudent*) = 0;//添加新客戶
virtual void delStudent(abstractstudent*) = 0;//刪除舊用戶
virtual void Notify() = 0;//給客戶通風報信
};
class student :public abstractstudent {//具體觀察者
private:
abstractmonitor* mor;
public:
student(abstractmonitor* mor) :mor(mor) {}
void update(int i) {
if (i == 0)
cout << "危險,隱蔽" << endl;
else
cout << "沒事兒,繼續耍" << endl;
}
};
class monitor:public abstractmonitor{ //具體監聽者
private:
vector<abstractstudent*> vecS;
vector<abstractstudent*>::iterator itS;
int State;
public:
void addStudent(abstractstudent* s) {
vecS.push_back(s);
}
void delStudent(abstractstudent* s) {
itS = vecS.begin();
while (itS != vecS.end())
{
if(*itS == s)
{
vecS.erase(itS);
break;
}
itS++;
}
}
void Notify() {
itS = vecS.begin();
while (itS != vecS.end())
{
(*itS)->update(State);
itS++;
}
}
void setState(int state)
{
State = state;
}
};
int main()
{
monitor* mor = new monitor();
student* stu1 = new student(mor);
student* stu2 = new student(mor);
mor->addStudent(stu1);
mor->addStudent(stu2);
mor->setState(1);
mor->Notify();
mor->delStudent(stu1);
mor->setState(0);
mor->Notify();
delete stu1;
delete stu2;
delete mor;
return 0;
}
應用場景
在以下任一情況下都可以使用觀察者模式:
- 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立的改變和複用;
- 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變;
- 當一個對象必須通知其它對象,而它又不能假定其它對象是誰;也就是說,你不希望這些對象是緊密耦合的。