观察者设计模式--学习笔记

 

意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

 

 

适用环境:

1)       当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

2)       当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

3)         当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

 

结构:

Observer的对象作为Subject的成员,然后通过observers调用Update函数,其实调用的是ConcreteObserverUpdate()函数,这正是C++中的多态的体现:基类指针调用派生类的函数;

        

         同样在ConcreteObserver中保存对ConCreteSubject的引用,这样通过subject就可以访问到ConcreteSubject中的GetState函数,这样SubjectObserver就可以相互访问了。注意不能定义Subject指针指向ConcreteSubject的对象,因为此时不能通过基类的指针访问ConcreteSubjecGetState函数,因为基类中没有这个函数;

 

   同时在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出现内存冲突,我没有仔细去检查问题,哪位解决了,也麻烦告诉我下,谢谢!


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值