编程模式大家都很熟悉,观察者模式也是经典中的经典,网络搜索观察者模式的实现代码也比比皆是,那么还有什么好说的呢。

这里我想实现的是一个能够广泛使用的观者者模式代码,也即拿来就能用,不用修改而且方便。目前常见的观察者模式大都是书写观者者和被观者者基类,完成观察、通知等操作。实际应用的时候,大都一个场景写一次,不能达到代码最大限度的复用思路。如下图(来源于网络):

主要问题出在Update,大部分情况,实现一个观察者模式,Update的时候都是要进行更新操作的,而更新操作时要看具体的ConcreateSubject的变化的,这个我们在写Subject类和Observer类的时候是无法预知的。所以这里Update无法传参,或者说无法传合适的参数能够达到代码写好就不再更改,而能满足各种情况的,话说这是模式6大原则中的哪条来着。或者Observer中记录着Subject的指针,Update的时候获取这一指针,然后据此获取ConcreateSubject的具体情况,这个貌似不错,只是也需要类型转换,而这样的做总是觉得不美的,Update是应用模式的关键代码位置,总是要继承重写的,能直接传过来需要的东西最好了。

说了半天,如何解决?不是说了要类型转换,然后不美么,解决类型问题即可。而提前预知子类类型好像也…,别忘记模板,写模板类可以提前定义类型,使用模板类完成观察者模式,一次编码,永久应用,且参数直接。不多说上代码:

// 观察者的抽象接口,实际的观察类根据需要继承CObserver和CMultiObserver

//

template<class T>

class  IObserver

{

public:

IObserver(){}

virtual  ~IObserver() {}

typedef T  SubjectType;

typedef IObserver<T> OBSERVER;

public:

//Subject通知Observer更新

friend  void  T::Notify();

//用来在Subject中注册和解注册Observer

friend  void  T::Attach(OBSERVER &Observer);

friend  BOOL  T::Dettach(OBSERVER &Observer);

friend  void  T::DetachAll();

protected:

//Observer根据Subject的变化更新

virtual void  Update (T *pSubject) = 0;

//用于被观察者进行回调的函数

virtual void  Attach(T *pSubject)  = 0;

virtual void  Dettach(T *pSubject) = 0;

};

// T为具体被观察者类型,具体Observer继承自Observer

// class ConcreteObserver : public Observer<Subject1>,public Observer<Subject2>

// {......}

// 观察同一个类的单个实例,但是可以观察不同类的实例

//

template <class T>

class  CObserver : public IObserver<T>

{

public:

CObserver():m_pSubject(NULL) {}

virtual  ~CObserver();

protected:

//Observer根据Subject的变化更新

virtual void  Attach(T *pSubject);

virtual void  Dettach(T *pSubject);

public:

//外界获取被观察的对象指针

SubjectType*  GetSubject();

protected:

SubjectType*  m_pSubject;

};

//可以观察多个实例

//

template <class T>

class  CMultiObserver : public IObserver<T>

{

public:

CMultiObserver(){}

virtual  ~CMultiObserver();

typedef vector<T*> Sub_vector;

typedef typename Sub_vector::iterator Sub_Iter;

protected:

//Observer根据Subject的变化更新

virtual void  Attach(T *pSubject);

virtual void  Dettach(T *pSubject);

public:

///获取被观察的对象的迭代器

Sub_Iter  SubBegin();

Sub_Iter  SubEnd();

protected:

//同一种类型的被观察者链表

Sub_vector    m_Subjects;

};

// Subject 是被观察者的基类

// T是被观察者的具现类

// class ConcreateSubject : public Subject<ConcreateSubject>

// {........}

//

template <class T>

class  CSubject

{

public:

CSubject() {}

virtual ~CSubject();

typedef  IObserver<T>   OBSERVER;

typedef  vector<OBSERVER *>   Obs_Vector;

typedef  typename  Obs_Vector::iterator Obs_Iterator;

public:

//进行双向连接的和取消连接的接口

void   Attach (OBSERVER &observer);

BOOL   Dettach(OBSERVER &observer);

void   DetachAll();

//在被观察者被修改后调用,通知观察者

void   Notify ();

//遍历获取观察者的指针和个数

int    GetObserverCount();

OBSERVER * GetObserver(int iIndex);

private:

//保存的所有的观察者的链表

Obs_Vector  m_observers;

};

/

//函数的具体实现

//

//CObserver的实现函数

template<class T>

CObserver<T>::~CObserver()

{

//通知被观察者,观察者退出了

if(NULL != m_pSubject)

m_pSubject->Dettach(*this);

}

template<class T>

void  CObserver<T>::Attach(T *pSubject)

{

m_pSubject = pSubject;

}

template<class T>

void  CObserver<T>::Dettach(T *pSubject)

{

ASSERT(m_pSubject == pSubject);

m_pSubject = NULL;

}

template<class T>

T*  CObserver<T>::GetSubject()

{

return m_pSubject;

}

//CMultiObserver的实现函数

template<class T>

CMultiObserver<T>::~CMultiObserver()

{

//通知所有的被观察者,观察者退出了

Sub_Iter iter = m_Subjects.begin();

while (iter != m_Subjects.end())

{

//如果不能找到目标,消除

(*iter)->Dettach(*this);

iter = m_Subjects.begin();

}

}

template <class T>

void  CMultiObserver<T>::Attach(T *pSubject)

{

m_Subjects.push_back(pSubject);

}

template <class T>

void  CMultiObserver<T>::Dettach(T *pSubject)

{

Sub_Iter iter = find(SubBegin(), SubEnd(), pSubject);

if(iter != SubEnd())

{

m_Subjects.erase(iter);

}

}

template <class T>

typename CMultiObserver<T>::Sub_Iter CMultiObserver<T>::SubBegin()

{

return m_Subjects.begin();

}

template <class T>

typename CMultiObserver<T>::Sub_Iter CMultiObserver<T>::SubEnd()

{

return m_Subjects.end();

}

//CSubject的实现函数

//用static_cast取消观察是因为析构时对象已经不完整了

template<class T>

CSubject<T>::~CSubject()

{

DetachAll();

}

template <class T>

void CSubject<T>::Attach (OBSERVER &observer)

{

//实现Observer和Subject的双向关联

m_observers.push_back(&observer);

observer.Attach(dynamic_cast<T*>(this));

}

template <class T>

BOOL CSubject<T>::Dettach(OBSERVER &observer)

{

//取消指定的Observer和Subject的双向连接

Obs_Iterator iter = find(m_observers.begin(),m_observers.end(),&observer);

//是否要对m_observers为空删除自身

if(iter == m_observers.end())

return  FALSE;

m_observers.erase(iter);

observer.Dettach(static_cast<T*>(this));

return true;

}

template <class T>

void CSubject<T>::Notify ()

{

//通知所有的观察者,被观察者被改变了

for_each(m_observers.begin(),

m_observers.end(),

bind2nd(mem_fun(&IObserver<T>::Update),dynamic_cast<T *>(this)));

}

template <class T>

int CSubject<T>::GetObserverCount()

{

return  (int)m_observers.size();

}

template <class T>

typename CSubject<T>::OBSERVER * CSubject<T>::GetObserver(int iIndex)

{

return m_observers[iIndex];

}

template <class T>

void  CSubject<T>::DetachAll()

{

//取消指定的Observer和Subject的双向连接

for_each(m_observers.begin(),

m_observers.end(),

bind2nd(mem_fun(&IObserver<T>::Dettach), static_cast<T *>(this)));

//最后清空连接

m_observers.clear();

}

应用实例:

class ASubject : public CSubject<ASubject>

{

//这里只需要写ASubject的东西,不用管被观察者这个角色的内容

}

Class BObserver : public CObserver<ASubject>

{

public:

/*这里,只需要继承CObserver<ASubject>的虚函数update,并且传参直接是ASubject指针,BObserver可以直接根据ASubject的情况进行自己的操作*/

virtual void Update(ASubject *subject);

}

实现调用:

ASubject a;

BObserver b;

a.Attach(b);

/*a的任意操作*/

a.Notify();//通知b,a更改了

这样,完成了观察者模式的调用,并且,实际应用的代码非常简单,几乎只用关心Update接口的实现,而且,Update中已经把ConcreateSubject指针传过来了。不用再进行恶心的类型转换。

这段代码几乎可以不用修改的适用于任何情况的观察者模式应用场景了。

不过,我已经很久不用这个模式了,从这个模式,我发展了一种消息树模式,可以覆盖观察者模式,而且更方便,更强大,适应范围更广,再写吧。

编程模式之观察者模式相关推荐

  1. 游戏编程模式 - 观察者模式

    edit date: 2019-12-04 14:59:39 0x00 观察者模式 新坑<游戏编程模式>(作者 Robert Nystrom). 在 Unity 下,用 C# 做了简单的实 ...

  2. 『设计模式』Web程序开发最基本的编程模式--MVC编程模式

    23种设计模式+额外常用设计模式汇总 (持续更新) 什么是MVC编程模式 ? MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controlle ...

  3. 【设计模式】设计模式C++编程实现之观察者模式(ObserverPattern)

    观察者模式定义: 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新. 观察者模式又叫做发布-订阅(Publish/Subscribe)模式.模型-视图( ...

  4. 《游戏编程模式》总结

    游戏编程模式 为什么要读这本书: 抽象和解耦能够使你的程序开发变得更快和更简单.但不要浪费时间来做这件事,除非你确信存在问题的代码需要这种灵活性. 在你的开发周期中要对性能进行思考和设计,但是要推迟那 ...

  5. 浅墨博客《游戏编程模式》

    https://blog.csdn.net/poem_qianmo/article/details/53240330 边看博客边阅读的中文版书籍,发现博客把我想了解的都总结了,而且还配有unity C ...

  6. 【游戏设计模式】之四 《游戏编程模式》全书内容提炼总结

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接: http://blog.csdn.net/poem_qianmo/article/details/53240330 作者:毛星云(浅 ...

  7. 【游戏设计模式】之 《游戏编程模式》全书内容提炼总结

    转自浅墨毛星云:http://blog.csdn.net/poem_qianmo/article/details/53240330 这是一篇超过万字读书笔记,总结了<Game Programmi ...

  8. 设计模式、原则、饿汉式单例模式、抽象工厂、代理模式、观察者模式、模板方法模式使用场景

    设计模式 ​ 对各种面向对象方法的一种总结.前辈们遇到了好多设计问题,然后利用面向对象解决了.然后他们把解决方案汇总起来,形成了20多种设计模式.它可以有效的帮助我们利用面向对象,来提高代码的复用性. ...

  9. 学习笔记-《游戏编程模式》

    <游戏编程模式>全书内容梗概总结 这是一篇超过万字读书笔记,总结了<游戏编程模式>一书中所有章节与内容的知识梗概. 目录与说明 <游戏编程模式>一书中总共介绍了19 ...

最新文章

  1. 关于使用Windows Live Writer
  2. 移植uboot第四步:设置NAND启动
  3. maven-eclipse 中index.html页面乱码
  4. Android开发之RecyclerView之刷新数据notifyDataSetChanged失败的问题
  5. 114实名认证未通过_企业微信怎么实名认证?实名认证后还可以改吗?
  6. Kongzue的APP拍照相册选择工具
  7. js tree选中子集默认选中上级_原生js实现轮播图(两种方法)
  8. 易筋SpringBoot 2.1 | 第廿四篇:SpringBoot访问Docker中的MongoDB
  9. 泛微OA常用js代码块
  10. 电子邮件(E-mail)和电子邮件协议
  11. java生成json格式数据 和 java遍历json格式数据
  12. telink wiki使用简单说明
  13. QQ导出的txt聊天记录导入数据库方法
  14. 在centos上安装pycharm
  15. scrapy框架—spiders
  16. 虎符WEB Writeup
  17. (内含两种方式)Android 在线查看文档world丶xls丶ppt等文件
  18. 做Android开发 需要掌握哪些知识
  19. 列表解析python_python列表解析式
  20. Trello中的Scrum

热门文章

  1. 嵌入式软件测试——1.简介
  2. 资料外泄:给系统管理者的警告
  3. 2020年二级计算机msoffice题库,2020年计算机等级MSOffice考试试题及参考答案
  4. 使用WebUploader实现图片上传
  5. Mac中Xcode如何更改编辑器文本字体大小
  6. wincc7.4安装授权 全(文件分享)
  7. uniapp实现登录功能步骤
  8. 项目1 设计简易灯箱画廊 实训要求: (1)利用超链接和图像标记设计简易灯箱画廊。 (2)给简易灯箱画廊增加背景音乐效果。
  9. 如何用Python画滑稽笑脸
  10. 来了老弟,帅气模态框