意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
适用环境:
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出现内存冲突,我没有仔细去检查问题,哪位解决了,也麻烦告诉我下,谢谢!