淺談觀察者模式
- 2020 年 3 月 11 日
- 筆記
前言:到目前已經看了幾個設計模式,像簡單工廠模式、策略模式、單一職責原則、開放-封閉原則、依賴倒轉與裝飾模式等。但總是紙上得來終覺淺的感覺,沒有深 刻的理解。到現在感覺是可以進一步學習面向對象語言編程的特性,如何抽象基 類、虛函數的應用、如何通過基類進行對象間的解耦、由此需要複習C++虛函數、 多態等特性。
一、基本信息
1. 什麼是觀察者模式
觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。當主題對象狀態發生變化時,會通知所有觀察者,使觀察者自己可以更新自己。

2. 觀察者模式特點(☆☆☆☆☆)
①什麼時候使用觀察者模式
當一個對象改變需要同時改變其他對象的時候。
當不知道有多少具體對象需要改變時,使用觀察者模式。
一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和復用。
②觀察者模式作用
主要是在解耦。讓耦合的雙方都依賴於抽象,而不依賴於具體(抽象耦合)。從而使各自的變化不會影響到另一邊的變化(依賴倒轉原則)。並建立了一套觸發機制。
個人理解,主要還是通過抽象基類進行解耦。
③缺點
如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間
觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
更新接口(update)只能統一調用,實際中並不一定統一。
二、程序實現
IDE使用Qt
1. 具體實現
抽象觀察者,為具體觀察者定義update接口,在得到主題通知時更新自己。
class Observer{public: Observer() {} virtual ~Observer() {} virtual void update() = 0;};
抽象主題為獨立模塊,僅與抽象觀察者耦合,維護觀察者列表,向眾多觀察者廣播事件。
class Subject{public: Subject() {} virtual ~Subject() {} public: //增加觀察者 void attachObserver(Observer *observer) {m_observersList.push_back(observer);} //移除觀察者 void detachObserver(Observer *observer) {m_observersList.remove(observer);} //通知 void notifyObsever(){ //C++11增加了range-for用法,簡化了遍歷寫法 for(Observer *iter : m_observersList) { iter->update(); } } private: //具體觀察者列表 list<Observer *> m_observersList;};
具體主題,設置相關狀態,並將狀態傳遞給具體觀察者。
class ConcreteSubject : public Subject{public: ConcreteSubject() {} virtual ~ ConcreteSubject() {} public: void setSubjectState(const string state) {m_subjectState = state;} string getSubjectState() {return m_subjectState;} private: string m_subjectState;};
具體觀察者,實現抽象觀察者的update接口,使自身狀態與主題狀態一致。具體觀察者需要保存相關具體主題,也可以保存多個。類似於可以關注多個公眾號。
class ConcreteObserver : public Observer{public: ConcreteObserver(ConcreteSubject *concreteSubject, string name): m_observerName(name),m_concreteSubject(concreteSubject) {} virtual ~ ConcreteObserver() {} public: virtual void update(){ //觀察者狀態由發佈者提供 m_observerState = m_concreteSubject->getSubjectState(); std::cout << "Observer " << m_observerName << " status is " << m_observerState << std::endl; } private: string m_observerName; //觀察者名稱 string m_observerState; //所觀察的具體主題,可觀察多個 ConcreteSubject *m_concreteSubject;};
2. 具體調用
int main(int argc, char *argv[]){ ConcreteSubject *s = new ConcreteSubject(); ConcreteObserver *observerA = new ConcreteObserver(s, "A"); //添加3個觀察者,更新狀態並通知 s->attachObserver(observerA); s->attachObserver(new ConcreteObserver(s, "B")); s->attachObserver(new ConcreteObserver(s, "C")); s->setSubjectState("start learn!"); s->notifyObsever(); //移除觀察者A,更新狀態並通知 s->detachObserver(observerA); s->setSubjectState("stop learn!"); s->notifyObsever(); QCoreApplication a(argc, argv); return a.exec();}

文章參考大話設計模式與網上資料,侵刪。
三、小結
直接看觀察者模式的實現所獲得的東西可能沒有那麼多,而且需要看很多遍,每次會有新的感悟。不妨看看大話設計模式的例子,從耦合的例子開始,看到最後面對這樣一個需求是如何從耦合變得不那麼耦合。有點數學定理公式,直接告訴你結果,但是卻不知道來源與具體應用場景。