观察者模式:

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

它有四种角色:

主题(Subject):一个接口,规定了具体主题需要实现的方法。

观察者(Observer):也是一个接口,规定了具体观察者用来更新数据的方法。

具体主题:实现主题接口的一个实例,比如本例中的“就业通知中心”;里面会维护一个具体观察者的集合。本文使用STL中的list。

具体观察者:实现观察者的一个实例,会包含存放主题的引用或者指针。

使用C++实现如下:

包含5个文件,头文件两个:主题类(Subject.h)观察者类(Observer.h)

源文件两个:主题类(Subject.cpp)观察者类(Observer.h)

一个测试文件。

//Subject.h

#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include "Observer.h"
#include <list>
#include <string>
using namespace std;
class Observer;//注意C++中虽然包含了头文件这里也需要声明
typedef list<Observer*> myList; class Subject{
public:
Subject(){}
virtual ~Subject(){}
virtual void addObserver(Observer* o) = 0;
virtual void deleteObserver(Observer* o) = 0;
virtual void notifyObservers() = 0; }; class SeekJobCenter : public Subject
{
public:
SeekJobCenter();
~SeekJobCenter(){}
void addObserver(Observer* o);
void deleteObserver(Observer* o); void notifyObservers();
void giveNewMessage(string str); private:
string mess;
bool changed;
myList personList; }; #endif

//Subject.cpp

//具体的主题
#include "stdafx.h"
#include "Subject.h"
#include "Observer.h"
#include <list> SeekJobCenter::SeekJobCenter()
{
mess = "";
changed = false;
}
void SeekJobCenter::addObserver(Observer* o)
{
list<Observer*>::iterator it;
//判断原始维护的list中是否存在添加的对象
it = find(personList.begin(), personList.end(), o);
if (it == personList.end())//不存在
{
personList.push_back(o);
}
return;
} void SeekJobCenter::deleteObserver(Observer* o)
{
list<Observer*>::iterator it;
it = find(personList.begin(), personList.end(), o);
if (it != personList.end())//存在
{
personList.remove(*it);
delete(*it);
}
return;
} void SeekJobCenter::notifyObservers()
{
list<Observer*>::iterator it;
if (changed)
{
for (it = personList.begin(); it != personList.end(); ++it)
{
(*it)->hearTelephone(mess);
}
changed = false;
}
return;
} void SeekJobCenter::giveNewMessage(string str)
{
if (0 == strcmp(str.c_str(), mess.c_str()))
{
changed = false;
}
else
{
mess = str;
changed = true;
}
return;
}

//Observer.h

#ifndef _OBSERVER_H_
#define _OBSERVER_H_
#include <string>
#include <iostream>
#include <list>
#include "Subject.h"
using namespace std;
class Subject;
/*
观察者基类
*/
class Observer
{
public:
Observer(){};
virtual ~Observer(){};
virtual void hearTelephone(string heardMess) = 0; }; class UniversityStudent : public Observer
{
public:
UniversityStudent(Subject* subject);
virtual ~UniversityStudent(){};
void hearTelephone(string heardMess); private:
Subject* subject; }; class HaiGui : public Observer
{
public:
HaiGui(Subject *subject);
virtual ~HaiGui(){};
void hearTelephone(string heardMess); private:
Subject *subject; }; #endif

//Observer.cpp

 #include "stdafx.h"
#include "Observer.h"
#include "Subject.h" UniversityStudent::UniversityStudent(Subject* subject)
{
if (NULL != subject)
{
this->subject = subject;
}
else
{
return;
} subject->addObserver(this);
}
void UniversityStudent::hearTelephone(string heardMess)
{
std::cout << "I am a university student" << std::endl;
std::cout << "I hear message is " << heardMess << std::endl;
return;
} HaiGui::HaiGui(Subject* subject)
{
if (NULL != subject)
{
this->subject = subject;
}
else
{
return;
}
subject->addObserver(this);
} void HaiGui::hearTelephone(string heardMess)
{
std::cout << "I am a HaiGui" << std::endl;
std::cout << "I hear message is " ;
cout << heardMess << endl;
return;
}

最后一个测试的文件:

#include "stdafx.h"
#include "Observer.h"
#include "Subject.h" int _tmain(int argc, _TCHAR* argv[])
{
SeekJobCenter *center = new SeekJobCenter();
UniversityStudent *chengchaolee = new UniversityStudent(center);
HaiGui *haigui = new HaiGui(center);
center->giveNewMessage("I need a cook");
center->notifyObservers();
center->giveNewMessage("I need a xxxx");
center->notifyObservers(); delete center;
delete chengchaolee;
delete haigui;
return 0;
}

定义两个具体的观察者,并且以具体主题作为参数,代表它观察的对象,然后当主题推送数据时,观察者就会收到消息,即“推数据”的方式,当然还有一种观察者模式采用的是拉数据,即由观察者自己定义需要什么数据,主题在notify的时候并不传递参数而是在观察者更新数据时,将Subject向下转换为具体Subject,从而获取其中相应的数据,这种方式叫做“拉数据”。

值得注意的是,C++在实现的时候,采用list存储具体观察者,需要使用list<Observer*>类型,即使用指针。不然会编译不通过,因为Observer是虚基类,无法实例化。

(一)观察者模式-C++实现的更多相关文章

  1. 23种设计模式--观察者模式-Observer Pattern

    一.观察者模式的介绍      观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...

  2. 谈谈JS的观察者模式(自定义事件)

    呼呼...前不久参加了一个笔试,里面有一到JS编程题,当时看着题目就蒙圈...后来研究了一下,原来就是所谓的观察者模式.就记下来...^_^ 题目 [附加题] 请实现下面的自定义事件 Event 对象 ...

  3. ObserverPattern(观察者模式)

    import java.util.ArrayList; import java.util.List; /** * 观察者模式 * @author TMAC-J * 牵一发而动全身来形容观察者模式在合适 ...

  4. java观察者模式

      像activeMQ等消息队列中,我们经常会使用发布订阅模式,但是你有没有想过,客户端时如何及时得到订阅的主题的信息?其实就里就用到了观察者模式.在软件系统中,当一个对象的行为依赖于另一个对象的状态 ...

  5. Backbone源码解析(六):观察者模式应用

    卤煮在大概一年前写过backbone的源码分析,里面讲的是对一些backbone框架的方法的讲解.这几天重新看了几遍backbone的源码,才发现之前对于它的理解不够深入,只关注了它的一些部分的细节和 ...

  6. PHP 高级编程(3/5) - 使用SPL(标准PHP库)实现观察者模式

    SPL(标准PHP库 - Standard PHP Library)是PHP5面向对象功能中重要的部分.原文解释是这样的“The Standard PHP Library (SPL) is a col ...

  7. 设计模式--观察者模式初探和java Observable模式

    初步认识观察者模式 观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明: 报社方负责出版报纸. 你订阅了该报社的报纸,那么只要报社发布了新报 ...

  8. 学C#之设计模式系列笔记(2)观察者模式

    一.借鉴说明 1.<Head First Design Patterns>(中文名<深入浅出设计模式>) 2.维基百科,观察者模式,https://zh.wikipedia.o ...

  9. PHP 观察者模式

    观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. [观察者模式中主要角色] 1.抽象主题(Subject)角色: 抽象主题提供了增加 ...

  10. GJM: 设计模式 - 观察者模式

    GJM : 观察者模式 视频地址: http://www.imooc.com/learn/415 本课程通过一个天气预报的发布和订阅案例,来讲解观察者模式在Java项目中的应用.主要包括观察者模式的结 ...

随机推荐

  1. 20款时尚的 WordPress 企业模板【免费主题下载】

    在这篇文章中,我们收集了20款时尚的 WordPress 企业模板.WordPress 作为最流行的博客系统,插件众多,易于扩充功能.安装和使用都非常方便,而且有许多第三方开发的免费模板,安装方式简单 ...

  2. 乱码之MyEclipse控制台

    今天突然发现控制台出现乱码,查了资料解决方案不一. 我的解决方案如下: Run -> Debug Configuration... -> MyEclipse Servler -> M ...

  3. 最简单的轮播广告(原生JS)

    改变每个图片的opacity属性:来自学友刘斌 素材图片: <!DOCTYPE html> <html lang="en"> <head> &l ...

  4. 【追寻javascript高手之路03】javascript对象大乱斗

    前言 昨天我们学习了下javascript中函数的参数与作用域的东东,现在回过头来看,其实都是与函数相关的,所以javascript中的函数仍然是王道,我们今天大概会发二篇或者三篇博客一起来巩固我们的 ...

  5. angular源码分析:angular的源代码目录结构说明

    一.读源码,是选择"编译合并后"的呢还是"编译前的"呢? 有朋友说,读angular源码,直接看编译后的,多好,不用管模块间的关系,从上往下读就好了.但是在我看 ...

  6. 深入理解javascript---命名函数表达式

    简单的说,命名函数表达式只有一个用户,那就是在Debug或者Profiler分析的时候来描述函数的名称,也可以使用函数名实现递归,但很快你就会发现其实是不切实际的.当然,如果你不关注调试,那就没什么可 ...

  7. [SharePoint] SharePoint 错误集 1

    1. Delete a site collection · Run command : Remove-SPSite –Identity http://ent132.sharepoint.hp.com/ ...

  8. Oracle function real_st_astext,解决ArcSDE中st_astext函数返回字符串结构异常问题

    项目过程中发现在Oracle中调用ArcSDE的st_astext函数返回ST_Geometry类型字段的WKT文本有时空间类型前缀没有返回,例如一个点的经度为113.4,纬度为30.6,调用st_a ...

  9. OC NSDictionary

    OC NSDictionary NSDictionary初始化 NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:@ ...

  10. LAMP配置虚拟目录

    1.  httpd.conf中添加 Listen 81 2. 1 <VirtualHost 127.0.0.2:81> 2 DocumentRoot E:\ws\2011\DiscuzSp ...