觀察者模式的程式例項C++ 以及觀察者模式與事件監聽的區別
一、什麼是觀察者模式 Observer模式也叫觀察者模式,它的作用是當一個物件的狀態發生變化時,可以自己主動通知其它關聯物件,自己主動重新整理物件狀態。
舉個樣例,使用者介面能夠作為一個觀察者,業務資料是被觀察者,使用者介面觀察業務資料的變化,發現數據變化後,就顯示在介面上。觀察者模式在模組之間劃定了清晰的界限,提高了應用程式的可維護性和重用性。
“觀察”不是“直接呼叫” 實現觀察者模式的時候要注意,觀察者和被觀察物件之間的互動關係不能體現成類之間的直接呼叫,否則就將使觀察者和被觀察物件之間緊密的耦合起來,從根本上違反面向物件的設計的原則。不管是觀察者“觀察”物件,還是被觀察者將自己的改變“通知”觀察者,都不應該直接呼叫。
實現觀察者模式的形式
實現觀察者模式有非常多形式,比較直觀的一種是使用一種“註冊——通知——撤銷註冊”的形式。
實現觀察者模式樣例
以下是C++的實現,在C++實現中,C++中沒有介面的概念,可是能夠用抽象類類取代Java或C#中的介面,在C++中抽象類中從派生類中抽象出來的函式(方法),必須定義成純虛擬函式,這樣在後面的使用中才幹夠通過基類的指標來訪問這些函式,面向物件的語言中有個特點,多型僅僅能訪問兩者中共同擁有的部分。
#include <iostream> #include <list> #include <string> using namespace std; class Observer; class Subject { public: virtual void attach(Observer *o) = 0; virtual void change() = 0; virtual void setWeather(string str) = 0; virtual string getWeather() = 0; }; class Observer { public: virtual string getName() = 0; virtual void update(Subject *s) = 0; }; class Earth: public Subject { private: string weather; list<Observer * > *l; //指標 public: Earth() { l = new list<Observer *>; } void attach(Observer *o) { this->l->push_back(o); }; void change() { for(list<Observer *>::iterator it = l->begin(); it != l->end(); ++it) { (*it)->update(this); } }; void setWeather(string str) { this->weather = str; change(); }; string getWeather() { return this->weather; }; }; class Satellite: public Observer { private: string name; public: Satellite(string str) { name = str; } string getName() { return name; }; void update(Subject *s) { cout << this->getName() + " " + s->getWeather(); } }; int main() { Earth e; Satellite *s1 = new Satellite("風雲一號"); Satellite *s2 = new Satellite("風雲二號"); Satellite *s3 = new Satellite("風雲三號"); Satellite *s4 = new Satellite("風雲四號"); e.attach(s1); e.attach(s2); e.attach(s3); e.attach(s4); e.setWeather("fine"); while(1) {} return 0; }
觀察者模式和事件監聽模式的區別
說到事件監聽模式,很容易將它和觀察者模式聯絡在一起。 實質上這兩者完成同類型的工作。依個人理解,事件監聽模式更像是觀察者模式的進階。 用一張圖來方便描述它們的區別:
觀察者模式中,‘主題’會在特定邏輯下通知所有‘觀察者’。 如果這個通知不包含任何資訊,那麼這種實現就是通常的觀察者模式。
class Subject { protected: void notify() { for (int i = 0; i < numObservers_; i++) { observers_[i]->onNotify(); } } };
如果‘主題’通知‘觀察者’的過程帶有一些<其他資訊>。那麼‘主題’本身已經上升成為了‘事件源’, 而通知中帶有的<其他資訊>經過封裝就成為了事件。
class Subject
{
protected:
void notify(const Entity& entity, Event event)
{
for (int i = 0; i < numObservers_; i++)
{
observers_[i]->onNotify(entity, event);
}
}
};
事件監聽模式的優勢: 在很多應用場景中,通知中附帶的<其他資訊>是必不可少的, 事件Event則對這些<資訊>進行了封裝,使它本身擁有了多型的特性。 每個事件物件就可以包含不同的資訊。但各個‘觀察者’提供給‘主題’的介面仍然是統一的 : onNotify(entity, event)
舉個簡單的例子,某遊戲中的成就係統包含兩種成就: 1.達成等級成就(觀察者1) 2.達成戰鬥力成就(觀察者2) 玩家(事件源)在完成升級時會建立兩個物件, 升級事件(包含玩家等級欄位) 戰鬥力提升事件(包含玩家當前戰鬥力欄位)。 成就係統收到事件後執行統一的邏輯: observers_[event.type]->OnAchieveEvent(entity, event); 總結來說 事件監聽機制就是對觀察者模式進行了進一步抽象,節省了程式碼量。 --------------------- 作者:AXuanK 來源:CSDN 原文:https://blog.csdn.net/AXuan_K/article/details/78803382 版權宣告:本文為博主原創文章,轉載請附上博文連結!