意圖:
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 所有依賴於它的對象都得到通知並被自動更新。
適用環境:
1) 當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。
2) 當對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。
3) 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。
結構:
Observer的對象作為Subject的成員,然後通過observers調用Update函數,其實調用的是ConcreteObserver的Update()函數,這正是C++中的多態的體現:基類指標調用衍生類別的函數;
同樣在ConcreteObserver中儲存對ConCreteSubject的引用,這樣通過subject就可以訪問到ConcreteSubject中的GetState函數,這樣Subject和Observer就可以相互訪問了。注意不能定義Subject指標指向ConcreteSubject的對象,因為此時不能通過基類的指標訪問ConcreteSubjec的GetState函數,因為基類中沒有這個函數;
同時在Subject類中通過List鏈表儲存觀察者,通過使用迭代器遍曆鏈表;實現所有的觀察者狀態的更新;
協作關係:
當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者。
在得到一個具體目標的改變通知後,ConcreteObserver對象可向目標物件查詢資訊,ConcreteObserver使用這些資訊以使它的狀態與目標對象的狀態保持一致;
發生改變請求的Observer對象並不立即更新,而是將其延遲到它從目標得到一個通知之後。
Notify 可以由目標對象(subject)觸發,也可以由使用者觸發;
程式源碼:
BaseSubject.h
#pragma once
#include "BaseObserver.h"
#include <list>
using namespace std;
class BaseSubject
{
public:
BaseSubject(void);
virtual ~BaseSubject(void);
/*
*/
virtual void Attach(BaseObserver*);
virtual void Detach(BaseObserver*);
virtual void Notify();
private:
list<BaseObserver*> *_observers;
};
BaseSubject.cpp 檔案
#include "StdAfx.h"
#include "BaseSubject.h"
BaseSubject::BaseSubject(void)
{
}
BaseSubject::~BaseSubject(void)
{
}
void BaseSubject::Attach (BaseObserver *o) {
_observers->push_back(o);
}
/*
*/
void BaseSubject::Detach (BaseObserver* o) {
list<BaseObserver*>::iterator iter;
for (iter=_observers->begin();iter!=_observers->end();iter++)
{
if ((*iter)==o)
{
_observers->erase(iter++);
}else
{
iter++;
}
}
}
/*
*/
void BaseSubject::Notify () {
//
list<BaseObserver*>::iterator iter;
for (iter=_observers->begin();iter!=_observers->end();iter++)
{
(*iter)->Update();
}
}
DerivedSubject.h檔案
#pragma once
class DerivedSubject
{
public:
DerivedSubject(void);
virtual ~DerivedSubject(void);
int GetState();
void SetState(int i);
int SubjectState;
};
DerivedSubject.cpp 檔案
#include "StdAfx.h"
#include "DerivedSubject.h"
DerivedSubject::DerivedSubject(void)
{
}
DerivedSubject::~DerivedSubject(void)
{
}
int DerivedSubject::GetState()
{
return SubjectState;
}
void DerivedSubject::SetState(int i)
{
SubjectState=i;
}
BaseObserver.h檔案
#pragma once
class BaseObserver
{
public:
BaseObserver(void);
BaseObserver(const BaseObserver&pt)
{
printf("");
}
virtual ~BaseObserver(void);
virtual void Update() = 0;
};
BaseObserver.cpp 檔案
#include "StdAfx.h"
#include "BaseObserver.h"
BaseObserver::BaseObserver(void)
{
}
BaseObserver::~BaseObserver(void)
{
}
DerivedObserver.h 檔案
#pragma once
#include "baseobserver.h"
#include "DerivedSubject.h"
class DerivedObserver :
public BaseObserver
{
public:
DerivedObserver(void);
virtual ~DerivedObserver(void);
void Update();
private:
int ObserverState;
DerivedSubject subject;
};
DerivedObserver.cpp 檔案
#include "StdAfx.h"
#include "DerivedObserver.h"
DerivedObserver::DerivedObserver(void)
{
}
DerivedObserver::~DerivedObserver(void)
{
}
void DerivedObserver::Update()
{
ObserverState=subject.GetState();
printf("ObserverState%d\n",ObserverState);
}
調用主函數:
// ObserverPattern.cpp : 定義控制台應用程式的進入點。
//
#include "stdafx.h"
#include "BaseSubject.h"
#include "DerivedSubject.h"
#include "BaseObserver.h"
#include "DerivedObserver.h"
int _tmain(int argc, _TCHAR* argv[])
{
BaseSubject *m_Subject=new BaseSubject();
DerivedSubject *m_ConcreteSubject=new DerivedSubject();
BaseObserver *m_Observer=new DerivedObserver();
m_ConcreteSubject->SetState(2);
printf("SubjectState%d\n",m_ConcreteSubject->SubjectState);
m_Subject->Attach(m_Observer);
m_Subject->Notify();
return 0;
}
程式中需要注意的問題引申:
1)vector順序容器,List順序容器,Map關聯容器的erase失效情況?
順序容器和關聯容器erase元素,注意:
vector順序容器erase元素後,不僅使所有指向被刪元素的迭代器失效,而且使被刪元素之後的所有迭代器失效,所以不能使用erase(iter++)的方法;
正確的用法:
for(iter=c.begin();iter!=c.end();)
{
iter=c.erase(iter);//erase 返回下一個有效迭代器;
}
關聯容器map: erase迭代器只是被刪元素的迭代器失效,但傳回值為void;所以要採用erase(iter++)的方式刪除迭代器;
for(iter=c.begin();iter!=c.end())
{
c.erase(iter++);
}
對應map
for(map<int ,string>::iterator iter=strmap.begin();iter!=strmap.end())
{
if(some_condition)
{
strmap.erase(iter++);
}else
{
iter++;
}
}
list erase只使得當前的節點失效,處理方法和map類似;
2)在程式中push_back出現記憶體衝突,我沒有仔細去檢查問題,哪位解決了,也麻煩告訴我下,謝謝!