注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mihooke's blog

IT之恋

 
 
 

日志

 
 

回调和观察者模式  

2017-04-11 21:13:19|  分类: C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
在C和C++中,回调是一个模块中的函数指针,可以调用另一个模块中的函数,并且后者不存在对前者的包含或链接依赖。回调的这种特性,使得低层代码能够执行与其不能有依赖关系的高层代码。比如,上位机程序需要调用算法DLL的函数进行处理工作,算法提供了相应头文件和DLL,我们在上位机程序中就可以使用函数指针来调用算法接口函数,而不用让整个工程包含算法DLL编译库,从而降低两者之间的耦合。
有时候,需要通过回调函数来传递参数,可以用一个“闭包”来解决,下面是一个例子:
class CallBackClass
{
public:
typedef void(*CallBackFunc)(char *str, void *data);
void SetCallBack(CallBackFunc, void *data);
private:
CallBackFunc m_cbf;
void *m_data;
};
使用:
if (m_cbf)
{
(*m_cbf)("mihooke", m_data);
}
不过C++中这种封装使用有一个问题,那就是非static成员函数自带this指针,因为this指针也需要传递,这时候当作回调函数会比较复杂,可以为每个成员函数创建一个static方法,并且使用额外的回调参数来传递this指针。

观察者模式
实际中,在C程序中使用回调函数多一些,在C++中,通常使用观察者模式来解决此类问题,观察者模式强调广播的作用,对象维护一个监控的列表,每当监控的对象发生变化,就通知观察者;这种设计模式要做的就是建立一对多的依赖关系,当一变化时,多都能收到变化的通知。下面是观察者模式示例代码:
Subject.h
#ifndef SUBJECT_H_
#define SUBJECT_H_
#include <string>
#include <list>
using namespace std;

class Observer;
class Subject
{
public:
virtual ~Subject();
virtual void AttachObserver(Observer *po);
virtual void DettachObserver(Observer *po);
virtual void Notify();
virtual void SetState(string &str) = 0;
virtual string GetState() = 0;
protected:
Subject();
private:
list<Observer*> *m_listObs;
};
class ConcreteSubject : public Subject
{
public:
ConcreteSubject();
~ConcreteSubject();
void SetState(string &str);
string GetState();
private:
string m_str;
};
#endif
Subject.cpp
#include "Observer.h"
#include "Subject.h"
#include <iostream>
using namespace std;

Subject::Subject() {m_listObs = new list<Observer*>;}
Subject::~Subject() {}
void Subject::AttachObserver(Observer *po) {m_listObs->push_front(po);}
void Subject::DettachObserver(Observer *po) {if(po!=NULL) m_listObs->remove(po);}
void Subject::Notify()
{
list<Observer*>::iterator itr = m_listObs->begin();
for (; itr != m_listObs->end(); ++itr)
{
(*itr)->Update(this);
}
}
///////////////////
ConcreteSubject::ConcreteSubject() {m_str = '\0';}
ConcreteSubject::~ConcreteSubject() {}
void ConcreteSubject::SetState(string &str) {m_str = str;}
string ConcreteSubject::GetState() {return m_str;}
Observer.h
#ifndef OBSERVER_H_
#define OBSERVER_H_
#include "Subject.h"
class Observer
{
public:
virtual ~Observer();
virtual void Update(Subject *ps) = 0;
virtual void PrintInfo() = 0;
protected:
Observer();
string m_str;
};
////////////////////
class ConcreteObserver1 : public Observer
{
public:
ConcreteObserver1(Subject *ps);
~ConcreteObserver1();
void Update(Subject *ps);
void PrintInfo();
Subject *GetSubject();
private:
Subject *m_sub;
};
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject *ps);
~ConcreteObserver2();
void Update(Subject *ps);
void PrintInfo();
Subject* GetSubject();
private:
Subject *m_sub;
};
#endif
Observer.cpp
#include "Observer.h"
#include "Subject.h"
#include <iostream>
using namespace std;

Observer::Observer() {m_str = '\0';}
Observer::~Observer() {}

ConcreteObserver1::ConcreteObserver1(Subject *ps) {m_sub = ps;m_sub->AttachObserver(this);}
ConcreteObserver1::~ConcreteObserver1() {m_sub->DettachObserver(this);if(m_sub!=NULL)delete m_sub;}
void ConcreteObserver1::Update(Subject *ps) {m_str = ps->GetState();PrintInfo();}
void ConcreteObserver1::PrintInfo() {cout<<"ConcreteObserver1::print "<<m_sub->GetState()<<endl;}
Subject *ConcreteObserver1::GetSubject() {return m_sub;}

ConcreteObserver2::ConcreteObserver2(Subject *ps) {m_sub = ps;m_sub->AttachObserver(this);}
ConcreteObserver2::~ConcreteObserver2() {m_sub->DettachObserver(this);if(m_sub!=NULL)delete m_sub;}
void ConcreteObserver2::Update(Subject *ps) {m_str = ps->GetState();PrintInfo();}
void ConcreteObserver2::PrintInfo() {cout<<"ConcreteObserver2::print "<<m_sub->GetState()<<endl;}
Subject *ConcreteObserver2::GetSubject() {return m_sub;}
main.cpp
#include "Observer.h"
#include "Subject.h"
#include <string>
using namespace std;

int main()
{
ConcreteSubject *pcs = new ConcreteSubject();
Observer *po1 = new ConcreteObserver1(pcs);
Observer *po2 = new ConcreteObserver2(pcs);
string str = "old";
pcs->SetState(str);
pcs->Notify();

str = "new";
pcs->SetState(str);
pcs->Notify();
return 0;
}
注意:pure virtual 不要在base class中实现!!!
一开始,创建的2个Observer对象都被存到了pcs对象的list中,pcs设置string为“old”,然后Notify通知观察者的2个子类,这2个子类输出观察的string值;当pcs设置string为“new”时,再Notify观察者的2个子类,再输出观察的string值,这是pcs自己的通知,也可以Observer对象调用Update来更新观察:
po1->Update(pcs);
po2->Update(pcs);//和调用Notify效果一样,因为Update就是获取当前Subject对象的string值,只不过这样需要每个观察者调用Update,pcs单次Notify就省事了,通知所有
  评论这张
 
阅读(43)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017