设计模式C++描述----04.观察者(Observer)模式
一. 概述
Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。

Sbuject 相当于通知者,它提供依赖于它的观察者Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。
Observer 相当于观察者,则提供一个Update操作,注意这里的 Observer 的 Update 操作并不在Observer 改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有 Observer 进行修改(调用Update)。
二. 举例
最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。
结构关系图如下:

DataSubject : 我们就认为是原始数据。
SheetObserver:就认为是表格,用来显示原始数据用的。
ChartObserver :就认为是图表,也是来显示原始数据的。
代码如下:
- //////////////////////////////////////////////////////////////////////////
 - //观察者基类
 - class Observer
 - {
 - public:
 - virtual ~Observer()
 - {
 - }
 - virtual void Update(Subject* sub) = 0;
 - virtual void PrintInfo() = 0;
 - protected:
 - Observer()
 - {
 - _st = '\0';
 - }
 - string _st;
 - };
 - //////////////////////////////////////////////////////////////////////////
 - //通知者基类
 - class Subject
 - {
 - public:
 - virtual ~Subject()
 - {
 - }
 - //注册观察者,这样通知者就能通知到观察者
 - virtual void Attach(Observer* obv)
 - {
 - _obvs->push_front(obv);
 - }
 - //注销观察者,通知者不再通知观察者
 - virtual void Detach(Observer* obv)
 - {
 - if (obv != NULL)
 - _obvs->remove(obv);
 - }
 - //通知操作,通知后对于每个注册过的观察者,将会调用自己的update方法
 - virtual void Notify()
 - {
 - list<Observer*>::iterator it;
 - it = _obvs->begin();
 - for (;it != _obvs->end();it++)
 - {
 - (*it)->Update(this);
 - }
 - }
 - virtual void SetState(const string& st) = 0;
 - virtual string GetState() = 0;
 - protected:
 - Subject()
 - {
 - _obvs = new list<Observer*>;
 - }
 - private:
 - list<Observer* >* _obvs;
 - };
 - //////////////////////////////////////////////////////////////////////////
 - //具体的数据通知者
 - class DataSubject:public Subject
 - {
 - public:
 - DataSubject()
 - {
 - _st = '\0';
 - }
 - ~DataSubject()
 - {
 - }
 - //自己的状态
 - string GetState()
 - {
 - return _st;
 - }
 - void SetState(const string& st)
 - {
 - _st = st;
 - }
 - private:
 - string _st;
 - };
 - //////////////////////////////////////////////////////////////////////////
 - //数据表格观察者
 - class SheetObserver:public Observer
 - {
 - public:
 - virtual Subject* GetSubject()
 - {
 - return _sub;
 - }
 - //构造函数里,把自己注册到通知者里
 - SheetObserver(Subject* sub)
 - {
 - _sub = sub;
 - _sub->Attach(this);
 - }
 - virtual ~SheetObserver()
 - {
 - _sub->Detach(this);
 - if (_sub != 0)
 - delete _sub;
 - }
 - //更新操作
 - void Update(Subject* sub)
 - {
 - _st = sub->GetState(); //具体的数据可以从Subject这个通知者中取
 - PrintInfo();
 - }
 - void PrintInfo()
 - {
 - cout<<"Sheet observer.... "<<_sub->GetState()<<endl;
 - }
 - private:
 - Subject* _sub;
 - };
 - //数据图表观察者
 - class ChatObserver:public Observer
 - {
 - public:
 - virtual Subject* GetSubject()
 - {
 - return _sub;
 - }
 - ChatObserver(Subject* sub)
 - {
 - _sub = sub;
 - _sub->Attach(this);
 - }
 - virtual ~ChatObserver()
 - {
 - _sub->Detach(this);
 - if (_sub != 0)
 - {
 - delete _sub;
 - }
 - }
 - //更新操作
 - void Update(Subject* sub)
 - {
 - _st = sub->GetState();
 - PrintInfo();
 - }
 - void PrintInfo()
 - {
 - cout<<"Chat observer.... "<<_sub->GetState()<<endl;
 - }
 - private:
 - Subject* _sub;
 - };
 - //////////////////////////////////////////////////////////////////////////
 - //测试
 - int main()
 - {
 - DataSubject* sub = new DataSubject();//数据通知者
 - Observer* o1 = new SheetObserver(sub);//表格观察者
 - Observer* o2 = new ChatObserver(sub);//图表观察者
 - sub->SetState("old data");//数据发生变化
 - sub->Notify();//通知者下发通知
 - sub->SetState("new data");
 - sub->Notify();
 - o1->Update(sub); //也可以由观察者自己调用更新函数
 - return 0;
 - }
 
说明:
1. 在 Observer 模式的实现中,Subject 维护一个 list 作为存储其所有观察者的容器。每当调用 Notify 操作就遍历 list中的 Observer 对象,并广播通知改变状态(调用Observer的Update操作)。
2. 运行示例程序,可以看到当原始数据 Subject 处于状态 “old” 时候,依赖于它的两个观察者都显示 “old”,当原始数据状态改变为 “new” 的时候,依赖于它的两个观察者也都改变为“new”。
3. 可以看到 Observer 与 Subject 互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体。
三. MFC中的观察者模式
MFC 的 View/Document 结构的实现中也采用了观察者模式。
Document 为模式中的通知者,管理应用程序中的数据,View为模式中的观察者,以给定的方显示所关联的
Document中的数据。CDocument类中定义了一个指针列表,用于保存对应的 CView
对象,并定义了一个函数用于对链表中的所有CView的对象进行更新。
结构如下:

原代码如下:
- //afxwin.h
 - class CDocument : public CCmdTarget
 - {
 - public:
 - // Operations
 - void AddView(CView* pView); //注册操作
 - void RemoveView(CView* pView); //注销操作
 - // Update Views (simple update - DAG only) //通知操作
 - void UpdateAllViews(CView* pSender, LPARAM lHint = 0L,
 - CObject* pHint = NULL);
 - protected:
 - CPtrList m_viewList; // list of views
 - }
 - //DocCore.cpp
 - void CDocument::AddView(CView* pView)
 - {
 - ASSERT_VALID(pView);
 - ASSERT(pView->m_pDocument == NULL); // must not be already attached
 - ASSERT(m_viewList.Find(pView, NULL) == NULL); // must not be in list
 - m_viewList.AddTail(pView); //加入链表中
 - ASSERT(pView->m_pDocument == NULL); // must be un-attached
 - pView->m_pDocument = this;
 - OnChangedViewList(); // must be the last thing done to the document
 - }
 - void CDocument::RemoveView(CView* pView)
 - {
 - ASSERT_VALID(pView);
 - ASSERT(pView->m_pDocument == this); // must be attached to us
 - m_viewList.RemoveAt(m_viewList.Find(pView)); //从链表中删除
 - pView->m_pDocument = NULL;
 - OnChangedViewList(); // must be the last thing done to the document
 - }
 - void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint)
 - // walk through all views
 - {
 - ASSERT(pSender == NULL || !m_viewList.IsEmpty());
 - // must have views if sent by one of them
 - POSITION pos = GetFirstViewPosition(); //遍历所有观察者
 - while (pos != NULL)
 - {
 - CView* pView = GetNextView(pos);
 - ASSERT_VALID(pView);
 - if (pView != pSender)
 - pView->OnUpdate(pSender, lHint, pHint);
 - }
 - }
 
从代码中我们可以看到,AddView 和 RemoveView 相当于注册和注销操作,UpdateAllViews 相当于通知操作,通知操作会依次调用各个CView 对象的 OnUpdate,进行更新。
设计模式C++描述----04.观察者(Observer)模式的更多相关文章
- 《Head First 设计模式》ch.2 观察者(Observer)模式
		
观察者模式 定义了对象之间一对多以来,这样一来,当一个对象改变状态时,它所有的依赖者都会收到通知并自动更新 设计原则-松耦合 松耦合将对象之间的互相依赖降到了最低——只要他们之间的接口仍被遵守 观察者 ...
 - Java 实现观察者(Observer)模式
		
1. Java自带的实现 类图 /** * 观察目标 继承自 java.util.Observable * @author stone * */ public class UpdateObservab ...
 - Java设计模式之从[星际争霸的兵种升级]分析观察者(Observer)模式
		
观察者模式定义对象的一种一对多的依赖关系.当一个对象的状态发生改变时.全部依赖于它的对象都会得到通知并被自己主动更新. 一个简单的样例是.在星际争霸的虫族中有一个0基础单位叫做跳狗(Zergling) ...
 - 观察者(Observer)模式
		
观察者模式又叫做发布-订阅模式(Publish.Subscribe)模式.模型-视图模式(Model/View)模式.源-监听器模式(Source/Listener)模式或从属者(Dependents ...
 - 《图解设计模式》读书笔记8-1 Observer模式
		
目录 示例程序 程序类图 程序 角色和类图 角色 类图 思路拓展 可复用性 Observer的顺序 MVC模式 Observer模式 Observer模式即观察者模式,该模式中,被观察者的状态发生变化 ...
 - 面向对象设计模式——观察者(OBSERVER)模式
		
定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...
 - 设计模式之观察者(OBSERVER)模式
		
定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. Observer模式描述了如何建立这种关系.这一模式中的关键对象是目标(subject ...
 - Head First 设计模式 —— 02. 观察者 (Observer) 模式
		
思考题 在我们的一个实现中,下列哪种说法正确?(多选) P42 public class WeatherDate { // 实例变量声明 public void measurementsChanged ...
 - java观察者(Observer)模式
		
观察者模式: 试想,在电子商务网站上,一个用户看中了一件一份,但是当时衣服的价格太贵,你需要将衣服收藏,以便等衣服降价时自动通知该用户.这里就是典型的观察模式的例子. 1.观察者模式的 ...
 
随机推荐
- JAVA线程通信之生产者与消费者
			
package cn.test.hf.test3; import java.util.concurrent.locks.Condition;import java.util.concurrent.lo ...
 - Spring MVC-从零开始-@RequestMapping 注解method属性
			
1.@RequestMapping 处理 HTTP 的各种方法(GET, PUT, POST, DELETE PATCH) package com.jt; import org.springfram ...
 - 《老师说的都对》第一次作业:OUC网上课程评价系统
			
项目介绍: 项目名称:OUC网上课程评价系统 项目概述:实现一个公开的网上课程评价系统.开课老师也可以在自己的课程主页填写自己的课程内容介绍,学生可以在课程页面中评价自己上过的课程.为想要选课的学生提 ...
 - 人人都是 API 设计师:我对 RESTful API、GraphQL、RPC API 的思考
			
原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 有一段时间没怎么写文章了,今天提笔写一 ...
 - MySql5.5安装步骤及MySql_Front视图配置
			
一.下载文件 有需要的朋友,请自行到百度云下载 链接:https://pan.baidu.com/s/13Cf1VohMz_a0czBI05UqJg 提取码:cmyq 二.安装MySql 2.1.运行 ...
 - 报错com.neenbedankt.android-apt not found如何解决
			
apply plugin: 'com.neenbedankt.android-apt' 在moudle中build.gradle文件内有应用此插件,编译时报错 检查Project中build.grad ...
 - 解决MVC中Model上的特性在EF框架刷新时清空的问题
			
MVC中关于前端数据的效验一般都是通过在Model中相关的类上打上特性来实现. 但是在我们数据库发生改变,EF框架需要刷新时会把我们在Model上的特性全部清除,这样的话,我们前端的验证就会失效. 因 ...
 - Jmeter Json List Element Assertion使用详解
			
使用背景: jmeter4.0本身提供json Assertion断言,但当我们想要对返回的json list中的多个字段进行断言的时候,我们就会感到很无力.那么此时我们就可以通过Json List ...
 - Hyper-V虚拟机win7网络红叉,无法上网解决方法
			
之前一直都是玩Vmware虚拟机,后来win8之后的系统有Hyper-V虚拟机就开始接触了. Windows 中内置的Hyper-V管理器可以说是给很多人带来了惊喜!至少运行的流畅程度要比Vmware ...
 - TP框架配合jquery进行3种方式的多图片上传
			
用的TP5.1框架+jquery 一 使用form表单方式进行多图片上传 html代码: <form action="../admin/admin/cs" enctype=& ...