觀察者模式(又被稱爲發佈-訂閱(Publish/Subscribe)模式,屬於行爲型模式的一種,它定義了一種一對多的依賴關係,讓多個觀察者對象同時監視某一個主題對象。這個主題對象的狀態變化時,會通知所有的觀察者對象,使他們能夠自動更新自己的狀態。
- 舉個例子:觀察者模式可以理解爲, 在一個一對多的關係模式中, 例如一個微信公衆號有多個關注用戶,那麼關注該微信公衆號的微信用戶就是觀察者,微信公衆號就是被觀察者.
- 一個微信公衆號會有多個關注用戶,這就是其中的一對多的關係.然後當一個對象的狀態發生改變就是說當被觀察者(微信公衆號)有了改變,例如添加了新的內容.這時候所有關注該公衆號的微信用戶就希望能得到通知.
- Subject:抽象主題(抽象被觀察者),抽象主題角色把所有觀察者對象保存在一個集合裏,每個主題都可以有任意數量的觀察者,抽象主題提供一個接口,可以增加和刪除觀察者對象。
- ConcreteSubject:具體主題(具體被觀察者),該角色將有關狀態存入具體觀察者對象,在具體主題的內部狀態發生改變時,給所有註冊過的觀察者發送通知。
- Observer:抽象觀察者,是觀察者者的抽象類,它定義了一個更新接口,使得在得到主題更改通知時更新自己。
- ConcrereObserver:具體觀察者,實現抽象觀察者定義的更新接口,以便在得到主題更改通知時更新自身的狀態。具體觀察者角色可以保存一個指向具體主題對象的引用。
C++程序
#include<iostream>
#include<list>
#include<algorithm>
#include<string>
using namespace std;
class Observer // 抽象觀察者,爲所有的觀察者定義更新接口 (Update),當收到 Subject 的通知時,Observer 需要同步更新信息。
{
public:
virtual ~Observer() = default;
virtual void Update() = 0;
};
class Subject // 抽象主題類,也是抽象被觀察者
{
public:
virtual ~Subject() = default;
virtual void Attach(Observer* observer) = 0;
virtual void Detach(Observer* observer) = 0;
virtual void Notify() = 0; //通知所有觀察者
};
class ConcreteSubject : public Subject // 具體主題類,也是具體被觀察者
{
private:
string subjectState;
list<Observer*> observers;
public:
void Attach(Observer* observer)override //添加觀察者
{
observers.push_back(observer);
}
void Detach(Observer* observer)override // 刪除觀察者
{
if(!observers.empty())
{
for (auto it = observers.begin(); it != observers.end(); ++it)
{
if (*it == observer)
{
observers.erase(it);
break;
}
}
}
}
void Notify() override //通知所有觀察者
{
if(!observers.empty())
{
for (auto item : observers)
{
item->Update(); // 更新當前具體主題對象的狀態到所有觀察者中
}
}
}
string GetSubjectState() //設置狀態
{
return subjectState;
}
void SetSubjectState(string state) // 獲得狀態
{
subjectState = state;
}
};
class ConcreterObserver : public Observer
{// 具體觀察者
private:
ConcreteSubject *m_subject;
string m_name;
public:
ConcreterObserver() = default;
ConcreterObserver(ConcreteSubject *subject, string name) : m_subject(subject),m_name(name) {}
void Update()override
{
// 具體主題對象狀態發生改變時,觀察者也發生改變。
auto observerState = m_subject->GetSubjectState();
cout << observerState << "," << m_name << "關閉股票行情,繼續工作!" << endl;
}
};
int main()
{
ConcreteSubject *huhansan = new ConcreteSubject;
ConcreterObserver *tongshi1 = new ConcreterObserver(huhansan, "魏關奼");
ConcreterObserver *tongshi2 = new ConcreterObserver(huhansan, "易管察");
ConcreterObserver *tongshi3 = new ConcreterObserver(huhansan, "霍華德");
huhansan->Attach(tongshi1);
huhansan->Attach(tongshi2);
huhansan->Attach(tongshi3);
//魏關奼沒有被老闆通知到,減去。
huhansan->Detach(tongshi1);
huhansan->SetSubjectState("我胡漢三回來了!");
huhansan->Notify();
delete huhansan;
delete tongshi1;
delete tongshi2;
delete tongshi3;
huhansan = nullptr;
tongshi1 = tongshi2 = tongshi3 = nullptr;
system("pause");
return 0;
}
結果
優點
觀察者模式解除了具體主題和具體觀察者的耦合
- 由於主題接口僅僅依賴於觀察者接口,因此具體主題只是知道它的觀察者是實現觀察者接口的某個類的實例,但不需要知道具體是哪個類。同樣,由於觀察者僅僅依賴於主題接口,因此具體觀察者只是知道它依賴的主題是實現主題接口的某個類的實例,但不需要知道具體是哪個類。
觀察者和被觀察者之間是抽象耦合的,容易擴展
- 觀察者模式滿足“開-閉原則”。主題接口僅僅依賴於觀察者接口,這樣,就可以讓創建具體主題的類也僅僅是依賴於觀察者接口,因此,如果增加新的實現觀察者接口的類,不必修改創建具體主題的類的代碼。同樣,創建具體觀察者的類僅僅依賴於主題接口,如果增加新的實現主題接口的類,也不必修改創建具體觀察者類的代碼。