用C++跟你聊聊“觀察者模型”

在這裏插入圖片描述
這篇會有點抽象,我搞了一下午。

從“狼來了”的故事說起

從前有一堆學生,下課偷偷打遊戲。但是他們的班主任卻總會在不該出現的時間,出現在不該出現的地點–教室後門。
這些學生實在忍無可忍了,他們想了一個辦法,買通了他們的班長,由班長爲他們放風,當然,誰要請班長放風,就得加入班長的放風小隊。一旦有任何風吹草動,班長就會立刻通知他們。
從此,他們過上了無憂無慮的生活,從此,他們與大學失之交臂。

故事中有那些元素呢?有放風的班長、請班長放風的學生、班長的通知名單、班長的通知狀態、學生的應對狀態,當然,特別重要的還有他們的班主任。

這些元素,便構成了今天這篇”觀察者模式“的主題。

觀察者模式

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;
}

應用場景

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

  • 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立的改變和複用;
  • 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變;
  • 當一個對象必須通知其它對象,而它又不能假定其它對象是誰;也就是說,你不希望這些對象是緊密耦合的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章