觀察者模式又被稱爲發佈訂閱模式。它定義了對象之間一對多的依賴,當一個對象狀態發生改變時,它的所有依賴者都會收到通知並自動更新相關內容。即建立一個(Subject類)對多(Observer類)的關係,能夠使得當Subject的對象變化的時候,依賴這個的多個Observe的對象實例也能夠同步進行相應的改變。
優點:
- 觀察者和被觀察者是抽象耦合的。
- 可以建立一套觸發機制。
缺點:
- 如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
- 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
- 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
哪些地方用到了觀察者模式?
觀察模式應用在一些框架中用的比較多,例如MFC的文檔視圖就, Qt的事件過濾,信號槽等。
下面是觀察者模式的實現代碼:
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Observer;
//抽象被觀察者
class Subject {
public:
virtual void Attach(Observer*) = 0;
virtual void Detach(Observer*) = 0;
virtual void Notify() = 0;
string GetState()
{
return "有新消息發佈: " + m_State;
}
void SetState(string state)
{
m_State = state;
}
protected:
std::list<Observer*> m_ObserverList;
string m_State;
};
//抽象觀察者
class Observer {
public:
Observer(Subject* sub) :m_Subject(sub) {}
virtual void Update() = 0;
protected:
Subject* m_Subject;
};
//具體觀察者1
class Observer1 : public Observer {
public:
Observer1(Subject* p_subject) : Observer(p_subject) {}
void Update() override
{
cout << "Observer1 get the update:" << m_Subject->GetState() << endl;
}
};
//具體觀察者2
class Observer2 : public Observer
{
public:
Observer2(Subject* p_subject) : Observer(p_subject) {}
void Update() override
{
cout << "Observer2 get the update:" << m_Subject->GetState() << endl;
}
};
//具體被觀察者
class ConcreteSubject : public Subject
{
public:
void Attach(Observer* pObserver) override
{
m_ObserverList.push_back(pObserver);
}
void Detach(Observer* pObserver) override
{
m_ObserverList.remove(pObserver);
}
void Notify() override;
};
//核心操作:循環通知所有觀察者
void ConcreteSubject::Notify()
{
auto it = m_ObserverList.begin();
while (it != m_ObserverList.end()) {
(*it++)->Update();
}
}
int main()
{
// 創建被觀察者
Subject* p_subject = new ConcreteSubject();
// 創建觀察者
Observer* p_observer1 = new Observer1(p_subject);
Observer* p_observer2 = new Observer2(p_subject);
// 改變狀態
p_subject->SetState("小米10發佈了");
// 註冊觀察者
p_subject->Attach(p_observer1);
p_subject->Attach(p_observer2);
p_subject->Notify();
// 註銷觀察值
p_subject->Detach(p_observer1);
p_subject->SetState("華爲P40發佈了");
p_subject->Notify();
delete p_observer1;
delete p_observer2;
delete p_subject;
return 0;
}
運行結果:
Observer1 get the update:有新消息發佈: 小米10發佈了
Observer2 get the update:有新消息發佈: 小米10發佈了
Observer2 get the update:有新消息發佈: 華爲P40發佈了
類圖關係:
一個被觀察者
多個觀察者