[C++设计模式]observer 观察者模式
有这么一种松耦合的需求:
有一些类的对象对类A对象的状态变化非常感兴趣,不会改变类A的对象,也不会被类A的对象改变,想以一种较小的代价观察对类A对象状态变化。
以下的几种方式也能实现上述目的
(1)通过类的继承来共同管理和维护一些感兴趣的数据或者状态,可是耦合度大。不易扩展和维护。
(2)通过调用被观察者的getter方法获取数据,这个还是直接的对象调用。
上述两种方法将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。不管是观察者“观察”观察对象。
还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
观察者模式(有时又被称为公布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式)中,一个目标物件管理全部相依于它的观察者物件,而且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
实现观察者模式有非常多形式,比較直观的一种是使用一种“注冊——通知——撤销注冊”的形式。陈硕的《linux多线程服务端编程 使用muduo c+网络库》中有一个多人聊天的样例。在服务端程序中,要把一个client发来的消息分发给全部的client,也能够看待是观察者模式的典型案例,TCP的连接视为注冊,消息的分发视为通知,TCP连接的断开视为撤销注冊。
观察者(Observer)将自己注冊到被观察对象(Subject)中。被观察对象将观察者存放在一个容器(Container)里。
被观察
被观察对象发生了某种变化(如图中的SomeChange),从容器中得到全部注冊过的观察者,将变化通知观察者。
撤销观察
观察者告诉被观察者要撤销观察。被观察者从容器中将观察者去除。
观察者将自己注冊到被观察者的容器中时,被观察者不应该过问观察者的详细类型,而是应该使用观察者的接口。这种长处是:假定程序中还有别的观察者,那么仅仅要这个观察者也是同样的接口实现就可以。一个被观察者能够相应多个观察者。当被观察者发生变化的时候,他能够将消息一一通知给全部的观察者。
基于接口。而不是详细的实现——这一点为程序提供了更大的灵活性。
C++样例
#include<iostream>
#include<set>
#include<string>
usingnamespacestd;
/////////////////////抽象模式定义
class CObservable;
//观察者,纯虚基类
classCObserver
{
public:
CObserver::CObserver(){};
virtualCObserver::~CObserver(){};
//当被观察的目标发生变化时,通知调用该方法
//来自被观察者pObs,扩展參数为pArg
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)=0;
};
//被观察者,即Subject
classCObservable
{
public:
CObservable():m_bChanged(false){};
virtual~CObservable(){};
//注冊观察者
voidAttach(CObserver*pObs);
//注销观察者
voidDetach(CObserver*pObs);
//注销全部观察者
voidDetachAll();
//若状态变化。则遍历观察者,逐个通知更新
voidNotify(void*pArg=NULL);
//測试目标状态是否变化
boolHasChanged();
//获取观察者数量
intGetObserversCount();
protected:
//设置状态变化!!!必须继承CObservable才干设置目标状态
voidSetChanged();
//初始化目标为未变化状态
voidClearChanged();
private:
boolm_bChanged;//状态
set<CObserver*>m_setObs;//set保证目标唯一性
};
/////////////////////抽象模式实现
voidCObservable::Attach(CObserver*pObs)
{
if(!pObs)return;
m_setObs.insert(pObs);
}
voidCObservable::Detach(CObserver*pObs)
{
if(!pObs)return;
m_setObs.erase(pObs);
}
voidCObservable::DetachAll()
{
m_setObs.clear();
}
voidCObservable::SetChanged()
{
m_bChanged=true;
}
voidCObservable::ClearChanged()
{
m_bChanged=false;
}
boolCObservable::HasChanged()
{
returnm_bChanged;
}
intCObservable::GetObserversCount()
{
returnm_setObs.size();
}
voidCObservable::Notify(void*pArg/*=NULL*/)
{
if(!HasChanged())return;
cout<<"notifyobservers…"<<endl;
ClearChanged();
set<CObserver*>::iteratoritr=m_setObs.begin();
for(;itr!=m_setObs.end();itr++)
{
(*itr)->Update(this,pArg);
}
}
/////////////////////详细应用类定义和实现
//bloger是公布者。即被观察者(subject)
classCBloger:publicCObservable
{
public:
voidPublish(conststring&strContent)
{
cout<<"blogerpublish,content:"<<strContent<<endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//portal是公布者。即被观察者(subject)
classCPortal:publicCObservable
{
public:
voidPublish(conststring&strContent)
{
cout<<"portalpublish,content:"<<strContent<<endl;
SetChanged();
Notify(const_cast<char*>(strContent.c_str()));
}
};
//RSS阅读器,观察者
classCRSSReader:publicCObserver
{
public:
CRSSReader(conststring&strName):m_strName(strName){}
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)
{
char*pContent=static_cast<char*>(pArg);
//观察多个目标
if(dynamic_cast<CBloger*>(pObs))
{
cout<<m_strName<<"updatedfrombloger,content:"<<pContent<<endl;
}
elseif(dynamic_cast<CPortal*>(pObs))
{
cout<<m_strName<<"updatedfromportal,content:"<<pContent<<endl;
}
}
private:
stringm_strName;
};
//Mail阅读器,观察者
classCMailReader:publicCObserver
{
public:
CMailReader(conststring&strName):m_strName(strName){}
virtualvoidUpdate(CObservable*pObs,void*pArg=NULL)
{
char*pContent=static_cast<char*>(pArg);
if(dynamic_cast<CBloger*>(pObs))
{
cout<<m_strName<<"updatedfrombloger,content:"<<pContent<<endl;
}
if(dynamic_cast<CPortal*>(pObs))
{
cout<<m_strName<<"updatedfromportal,content:"<<pContent<<endl;
}
}
private:
stringm_strName;
};
/////////////////Main
intmain()
{
//目标(被观察者)
CBloger*pBloger=newCBloger();
CPortal*pPortal=newCPortal();
//观察者.一个观察者能够观察多个目标
CRSSReader*pRssReader=newCRSSReader("rssreader");
CMailReader*pMailReader=newCMailReader("mailreader");
pBloger->Attach(pRssReader);//bloger注冊观察者
pBloger->Attach(pMailReader);//bloger注冊观察者
pPortal->Attach(pRssReader);//portal注冊观察者
pPortal->Attach(pMailReader);//portal注冊观察者
//博客公布信息
pBloger->Publish("博客分享设计模式");
cout<<endl;
//门户公布信息
pPortal->Publish("门户分享设计模式");
cout<<"\nportaldetachedmailreader"<<endl;
pPortal->Detach(pMailReader);
cout<<"portalobserverscount:"<<pPortal->GetObserversCount()<<endl<<endl;
pPortal->Publish("门户分享设计模式");
system("pause");
return0;
}
[C++设计模式]observer 观察者模式的更多相关文章
- C++设计模式-Observer观察者模式
Observer观察者模式作用:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 UML图: S ...
- Java 设计模式 – Observer 观察者模式
目录 [隐藏] 1 代码 1.1 观察者接口: 1.2 被观察者: 1.3 观众类 : 1.4 电影类: 1.5 效果如下: 代码 说明都在注释: 观察者接口: package ObserverMod ...
- 委托、事件、Observer观察者模式的使用解析二
一.设计模式-Observer观察者模式 Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新.Observer模式是一种 ...
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 设计模式之观察者模式(Observable与Observer)
设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
- 设计模式18:Observer 观察者模式(行为型模式)
Observer 观察者模式(行为型模式) 动机(Motivation) 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有依赖对象(观察者对象) ...
- java设计模式解析(1) Observer观察者模式
设计模式系列文章 java设计模式解析(1) Observer观察者模式 java设计模式解析(2) Proxy代理模式 java设计模式解析(3) Factory工厂模式 java设计模式解析( ...
- java设计模式之观察者模式
观察者模式 观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.在此种模 ...
随机推荐
- solaris 10 关闭ftp、telnet
安装solaris10,启动后发现找不到ftp.telnet的关闭方法, 管理命令 svcadm(服务状态管理,启动.停止等) # svcs 查看当前所有的服务状态,可以使用|管道符重定向作更个性化的 ...
- Super超级ERP系统---(1)总体设计
1.概述 随着互联网的发展,尤其是电子商务的发展,信息化系统越来显得越重要.在互联网飞速发展的今天,各种网站,软件系统应用而生,特别是随着近几年电子商务的发展,很多企业慢慢开始做大,管理方面暴露 ...
- lua的Metatables和Metamethods
Metatable: lua中的每一个表都有其Metatable,默认情况下Metatable为nil.可通过setmetatable函数设置或者改变一个表的Metatable, 也可以通过getme ...
- 洛谷P4413 [COCI2006-2007#2] R2(可持久化平衡树维护NTT)
题意翻译 设S=(R1+R2)/2,给定R1与S (-1000<=R1,S<=1000)(−1000<=R1,S<=1000) ,求R2. 感谢@Xeonacid 提供的翻译 ...
- javascript中对象两种创建方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 微信小程序开发之animation动画实现
1. 创建动画实例 wx.createAnimation(OBJECT) 创建一个动画实例animation.调用实例的方法来描述动画.最后通过动画实例的export方法导出动画数据传递给组件的ani ...
- vs添加浏览器
点击桌面谷歌图标,查看属性,赋值全部地址 在vs中,直接添加,把地址复制进去就ok了
- spring的HandlerMapping
handerlMapping意思是处理器映射,是把请求的url地址与方法进行映射,如SimpleUrlHandlerMapping.
- 优动漫PAINT如何打开图形文件
优动漫PAINT也就是我们常说的clip studio paint(CSP)的中文版本,在优动漫PAINT软件中打开文件的方式有很多,您可以直接拖拽至优动漫PAINT界面或者文档窗口,也可以执行文件菜 ...
- Java中数组的反转
public class ArrayDemo2 { public static void main(String[] args) { //定义一个数组存放元素 int[] arr3 = {10, 20 ...