C++設(shè)計(jì)模式之觀察者模式
前言
之前做了一個(gè)性能測(cè)試的項(xiàng)目,就是需要對(duì)現(xiàn)在的產(chǎn)品進(jìn)行性能測(cè)試,獲得測(cè)試數(shù)據(jù),然后書(shū)寫(xiě)測(cè)試報(bào)告,并提出合理化的改善意見(jiàn)。項(xiàng)目很簡(jiǎn)單,我們獲得了一系列性能測(cè)試數(shù)據(jù),對(duì)于數(shù)據(jù),我們需要在Excel中制作測(cè)試數(shù)據(jù)的折線圖、餅狀圖和柱狀圖,以直觀的表現(xiàn)出性能的變化。在實(shí)際操作時(shí),我發(fā)現(xiàn),如果我修改了一個(gè)數(shù)據(jù),折線圖、餅狀圖和柱狀圖就都發(fā)生了變換。這個(gè)是如何做到的?這就要說(shuō)到今天總結(jié)的觀察者模式了,作為設(shè)計(jì)模式大家庭中最重要的一個(gè),我們不得不去好好的學(xué)習(xí)一下觀察者模式。
觀察者模式
在GOF的《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書(shū)中對(duì)觀察者模式是這樣說(shuō)的:定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。當(dāng)一個(gè)對(duì)象發(fā)生了變化,關(guān)注它的對(duì)象就會(huì)得到通知;這種交互也稱為發(fā)布-訂閱(publish-subscribe)。目標(biāo)是通知的發(fā)布者,它發(fā)出通知時(shí)并不需要知道誰(shuí)是它的觀察者。
再說(shuō)說(shuō)上面的數(shù)據(jù)和圖之間的關(guān)系;不管是折線圖、餅狀圖,還是柱狀圖,它們都依賴于數(shù)據(jù);當(dāng)數(shù)據(jù)發(fā)生變化時(shí),數(shù)據(jù)對(duì)象會(huì)通知依賴于它的對(duì)象去更新;所以就有了Excel中,當(dāng)數(shù)據(jù)發(fā)生變化時(shí),對(duì)應(yīng)的統(tǒng)計(jì)圖也會(huì)自動(dòng)的重繪。
UML類圖
Subject(目標(biāo))
——目標(biāo)知道它的觀察者??梢杂腥我舛鄠€(gè)觀察者觀察同一個(gè)目標(biāo);
——提供注冊(cè)和刪除觀察者對(duì)象的接口。
Observer(觀察者)
——為那些在目標(biāo)發(fā)生改變時(shí)需獲得通知的對(duì)象定義一個(gè)更新接口。
ConcreteSubject(具體目標(biāo))
——將有關(guān)狀態(tài)存入各ConcreteObserver對(duì)象;
——當(dāng)它的狀態(tài)發(fā)生改變時(shí),向它的各個(gè)觀察者發(fā)出通知。
ConcreteObserver(具體觀察者)
——維護(hù)一個(gè)指向ConcreteSubject對(duì)象的引用;
——存儲(chǔ)有關(guān)狀態(tài),這些狀態(tài)應(yīng)與目標(biāo)的狀態(tài)保持一致;
——實(shí)現(xiàn)Observer的更新接口以使自身狀態(tài)與目標(biāo)的狀態(tài)保持一致。
觀察者模式按照以下方式進(jìn)行協(xié)作:
1.當(dāng)ConcreteSubject發(fā)生任何可能導(dǎo)致其觀察者與其本身狀態(tài)不一致的改變時(shí),它將通知它的各個(gè)觀察者;
2.在得到一個(gè)具體目標(biāo)的改變通知后,ConcreteObserver對(duì)象可向目標(biāo)對(duì)象查詢信息。ConcreteObserver使用這些信息以使它的狀態(tài)與目標(biāo)對(duì)象的狀態(tài)一致。
以下是調(diào)用時(shí)序圖:
使用場(chǎng)合
在以下任一情況下都可以使用觀察者模式:
1.當(dāng)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一方面。將這二者封裝在獨(dú)立的對(duì)象中以使它們可以各自獨(dú)立的改變和復(fù)用;
2.當(dāng)對(duì)一個(gè)對(duì)象的改變需要同時(shí)改變其它對(duì)象,而不知道具體有多少對(duì)象有待改變;
3.當(dāng)一個(gè)對(duì)象必須通知其它對(duì)象,而它又不能假定其它對(duì)象是誰(shuí);也就是說(shuō),你不希望這些對(duì)象是緊密耦合的。
代碼實(shí)現(xiàn)
#include <iostream>
#include <list>
using namespace std;
class Observer
{
public:
virtual void Update(int) = 0;
};
class Subject
{
public:
virtual void Attach(Observer *) = 0;
virtual void Detach(Observer *) = 0;
virtual void Notify() = 0;
};
class ConcreteObserver : public Observer
{
public:
ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}
void Update(int value)
{
cout<<"ConcreteObserver get the update. New State:"<<value<<endl;
}
private:
Subject *m_pSubject;
};
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}
void Update(int value)
{
cout<<"ConcreteObserver2 get the update. New State:"<<value<<endl;
}
private:
Subject *m_pSubject;
};
class ConcreteSubject : public Subject
{
public:
void Attach(Observer *pObserver);
void Detach(Observer *pObserver);
void Notify();
void SetState(int state)
{
m_iState = state;
}
private:
std::list<Observer *> m_ObserverList;
int m_iState;
};
void ConcreteSubject::Attach(Observer *pObserver)
{
m_ObserverList.push_back(pObserver);
}
void ConcreteSubject::Detach(Observer *pObserver)
{
m_ObserverList.remove(pObserver);
}
void ConcreteSubject::Notify()
{
std::list<Observer *>::iterator it = m_ObserverList.begin();
while (it != m_ObserverList.end())
{
(*it)->Update(m_iState);
++it;
}
}
int main()
{
// Create Subject
ConcreteSubject *pSubject = new ConcreteSubject();
// Create Observer
Observer *pObserver = new ConcreteObserver(pSubject);
Observer *pObserver2 = new ConcreteObserver2(pSubject);
// Change the state
pSubject->SetState(2);
// Register the observer
pSubject->Attach(pObserver);
pSubject->Attach(pObserver2);
pSubject->Notify();
// Unregister the observer
pSubject->Detach(pObserver);
pSubject->SetState(3);
pSubject->Notify();
delete pObserver;
delete pObserver2;
delete pSubject;
}
總結(jié)
觀察者模式在23個(gè)設(shè)計(jì)模式中的地位是非常高的,我們基本上各大框架中都是隨處可見(jiàn)。真正的理解了整個(gè)模式,對(duì)我們?nèi)ダ斫鈩e人的代碼有非常大的幫助;在我們?nèi)蘸蟮墓ぷ髦幸矔?huì)或多或少的使用該設(shè)計(jì)模式。這里總結(jié)的不是很全面,在日后如果碰到了需要補(bǔ)充的內(nèi)容,我會(huì)繼續(xù)補(bǔ)充的;同時(shí)也希望大家提出更好的建議。
相關(guān)文章
C++制作鼠標(biāo)連點(diǎn)器實(shí)例代碼
大家好,本篇文章主要講的是C++制作鼠標(biāo)連點(diǎn)器實(shí)例代碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01static_cast,dynamic_cast,reinterpret_cast,const_cast的區(qū)別及用法詳解
以下是對(duì)static_cast,dynamic_cast,reinterpret_cast,const_cast的區(qū)別及用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09推薦幾款C/C++的編譯器、編譯環(huán)境(非常全面的比較)
這篇文章主要介紹了C/C++編譯器的一些易混淆概念,這里腳本之家小編特為大家分享一下,需要的朋友可以參考下2021-06-06C++?構(gòu)造函數(shù)學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++?構(gòu)造函數(shù)學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10C++ 多線程編程建議之 C++ 對(duì)多線程/并發(fā)的支持(下)
這篇文章主要介紹的是 C++ 多線程編程建議之 C++ 對(duì)多線程/并發(fā)的支持的相關(guān)資料,承接前文 現(xiàn)代 C++ 對(duì)多線程/并發(fā)的支持,接下來(lái)我們看看回發(fā)生什么吧2021-10-10C++中char*轉(zhuǎn)換為L(zhǎng)PCWSTR的解決方案
最近在學(xué)習(xí)C++,遇到了一個(gè)char*轉(zhuǎn)換為L(zhǎng)PCWSTR的問(wèn)題,通過(guò)查找資料終于解決了,所以下面這篇文章主要介紹了C++中char*轉(zhuǎn)LPCWSTR的解決方案,文中通過(guò)詳細(xì)的示例代碼介紹的很詳細(xì),有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-01-01