Chapter10:观察者模式
观察者模式,又叫做发布-订阅(Publish/Subscribe)模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使得它们能够自动更新自己。
观察者模式的动机
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不方便。而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
什么时候应该使用观察者模式
当一个对象的改变需要同时改变其他对象的时候。而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。也可以理解为,当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。总的来说,观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
实际应用
工程结构
(1)抽象通知者Subject.h
(2)抽象观察者Observer.h
(3)具体通知者ConcreteSubject.h
(4)具体观察者ConcreteObserver.h
(5)客户端类ObserverApp.cpp
(1)抽象通知者Subject.h
* description: 主题或者抽象通知者类,一般用一个抽象类或者一个接口实现。
它把所有对观察者对象的引用保存在一个聚集里,每个主题都
可以有任何数量的观察者。抽象主题提供一个接口,可以增加
或者删除观察者对象。
* remark:
************************************************************************/
#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include "Observer.h"
#include <list>
#include <string>
#include <iostream>
using namespace std;
class CSubject
{
public:
// 增加观察者
virtual void Attach(CObserver* pObserver) = 0;
// 移除观察者
virtual void Detach(CObserver* pObserver) = 0;
// 通知
virtual void Notify(void) = 0;
};
#endif //_SUBJECT_H_
(2)抽象观察者Observer.h
* description: 抽象观察者类,为所有的具体观察者定义一个接口,在得到主题
的通知时更新自己
* remark:
************************************************************************/
#ifndef _OBSERVER_H_
#define _OBSERVER_H_
class CObserver
{
public:
virtual void Update() = 0;
};
#endif //_OBSERVER_H_
(3)具体通知者ConcreteSubject.h
* description: 具体主题类或者具体通知者,将有关状态存入具体观察者对象;在
具体主题的内部状态改变时,给所有登记过的观察者发出通知。
* remark:
************************************************************************/
#ifndef _CONCRETE_SUBJECT_H_
#define _CONCRETE_SUBJECT_H_
#include "Subject.h"
class CConcreteSubject : public CSubject
{
public:
// 增加观察者
void Attach(CObserver* pObserver)
{
m_listObservers.push_back(pObserver);
}
// 移除观察者
void Detach(CObserver* pObserver)
{
m_listObservers.remove(pObserver);
}
// 通知
void Notify(void)
{
list<CObserver*>::iterator lIter;
for (lIter = m_listObservers.begin(); lIter != m_listObservers.end(); lIter++)
{
(*lIter)->Update();
}
}
void SetState(const string& strState)
{
m_strSubjectState = strState;
}
string GetState(void)
{
return m_strSubjectState;
}
private:
string m_strSubjectState;
list<CObserver*> m_listObservers;
};
#endif //_CONCRETE_SUBJECT_H_
(4)具体观察者ConcreteObserver.h
* description: 具体观察者,实现抽象观察者角色所要求的更新接口,以便使本
身的状态与主题的状态相协调。具体观察者角色可以保存一个指
向具体主题对象的引用
* remark:
************************************************************************/
#ifndef _CONCRETE_OBSERVER_H_
#define _CONCRETE_OBSERVER_H_
#include "ConcreteSubject.h"
class CConcreteObserver : public CObserver
{
public:
CConcreteObserver(CConcreteSubject* pSubject, const string& strName)
{
m_pSubject = pSubject;
m_strName = strName;
}
void Update(void)
{
if (NULL != m_pSubject)
{
m_strObserverState = m_pSubject->GetState();
cout << "观察者【" << m_strName << "】的新通知:" << m_strObserverState << endl;
}
}
CConcreteSubject* GetSubject(void)
{
return m_pSubject;
}
void SetSubject(CConcreteSubject* pSubject)
{
m_pSubject = pSubject;
}
private:
string m_strName;
string m_strObserverState;
CConcreteSubject* m_pSubject;
};
#endif //_CONCRETE_OBSERVER_H_
(5)客户端类ObserverApp.cpp
//
#include "stdafx.h"
#include "ConcreteSubject.h"
#include "ConcreteObserver.h"
void FreeMemory(void* Pointer)
{
if (NULL != Pointer)
{
free(Pointer);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CConcreteSubject* pConcreteSubject = NULL;
pConcreteSubject = new CConcreteSubject();
CConcreteObserver* pConcreteObserver1 = NULL;
pConcreteObserver1 = new CConcreteObserver(pConcreteSubject, "Alice");
CConcreteObserver* pConcreteObserver2 = NULL;
pConcreteObserver2 = new CConcreteObserver(pConcreteSubject, "Bob");
CConcreteObserver* pConcreteObserver3 = NULL;
pConcreteObserver3 = new CConcreteObserver(pConcreteSubject, "Carey");
pConcreteSubject->Attach(pConcreteObserver1);
pConcreteSubject->Attach(pConcreteObserver2);
pConcreteSubject->Attach(pConcreteObserver3);
pConcreteSubject->Detach(pConcreteObserver3);
pConcreteSubject->SetState("快休息~");
pConcreteSubject->Notify();
system("pause");
FreeMemory(pConcreteObserver1);
FreeMemory(pConcreteObserver2);
FreeMemory(pConcreteObserver3);
FreeMemory(pConcreteSubject);
return 0;
}
观察者模式的不足
尽管已经用了依赖倒转原则,但是“抽象通知者”还是依赖“抽象观察者”,也就是说,万一没有了抽象观察者这样的接口,通知的功能就完成不了。另外每个具体观察者,它不一定是“更新”的方法要调用。比如:我们的VS开发工具,当我们调式程序时,希望是“工具箱”隐藏,“自动窗口”打开,这根本就不是同名的方法。这就是不足的地方。如果通知者和观察者之间根本就相互不知道,由客户端来决定通知谁。
事件委托:
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。一个委托可以搭载多个方法,所有方法被依次唤起。可以使得委托对象所搭载的方法并不需要属于同一个类。委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。
模式优化
工程结构
(1)通知者类
(2)观察者类
(3)客户端类
(1)通知者类
* description: 具体主题类或者具体通知者,将有关状态存入具体观察者对象;在
具体主题的内部状态改变时,给所有登记过的观察者发出通知。
* remark:
************************************************************************/
#ifndef _CONCRETE_SUBJECT_H_
#define _CONCRETE_SUBJECT_H_
#include <map>
using namespace std;
class Observer;
class CSubject
{
public:
void AddObserver(Observer* pOb, void (Observer::*pMemFunc)())
{
m_MapOb.insert(pair<Observer*, void (Observer::*)()>(pOb, pMemFunc));
}
void Notify(void)
{
ObIter Iter = m_MapOb.begin();
for (; Iter != m_MapOb.end(); Iter++)
{
void (Observer::*pMemFunc)() = Iter->second;
(Iter->first->*pMemFunc)();
}
}
string GetSubject(void)
{
return m_strSubject;
}
void SetSubject(const string& strSubject)
{
m_strSubject = strSubject;
}
private:
map<Observer*, void (Observer::*)()> m_MapOb;
typedef map<Observer*, void (Observer::*)()>::iterator ObIter;
string m_strSubject;
};
#endif //_CONCRETE_SUBJECT_H_
(2)观察者类
* description:
* remark:
************************************************************************/
#ifndef _CONCRETE_OBSERVER_H_
#define _CONCRETE_OBSERVER_H_
#include <string>
#include <iostream>
using namespace std;
class Observer
{
// do nothing
};
class CSubject;
class CObserverA : public Observer
{
public:
CObserverA(const string& strName, CSubject* pSubject)
{
m_strName = strName;
m_pSubject = pSubject;
}
void UpdateOfObserverA(void)
{
if (NULL != m_pSubject)
{
cout << m_pSubject->GetSubject() << m_strName << "别打魔兽争霸了" << endl;
}
}
private:
string m_strName;
CSubject* m_pSubject;
};
class CObserverB : public Observer
{
public:
CObserverB(const string& strName, CSubject* pSubject)
{
m_strName = strName;
m_pSubject = pSubject;
}
void UpdateOfObserverB(void)
{
if (NULL != m_pSubject)
{
cout << m_pSubject->GetSubject() << m_strName << "别打魔兽世界了" << endl;
}
}
private:
string m_strName;
CSubject* m_pSubject;
};
#endif //_CONCRETE_OBSERVER_H_
(3)客户端类
//
#include "stdafx.h"
#include "Subject.h"
#include "ConcreteObserver.h"
void FreeMemory(void* Pointer)
{
if (NULL != Pointer)
{
free(Pointer);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CSubject ObjBoss;
CObserverA* pObA = NULL;
pObA = new CObserverA("Alice", &ObjBoss);
CObserverB* pObB = NULL;
pObB = new CObserverB("Bob", &ObjBoss);
ObjBoss.AddObserver(pObA, (void (Observer::*)())&CObserverA::UpdateOfObserverA);
ObjBoss.AddObserver(pObB, (void (Observer::*)())&CObserverB::UpdateOfObserverB);
ObjBoss.SetSubject("你妈喊你回家吃饭!");
ObjBoss.Notify();
system("pause");
FreeMemory(pObB);
FreeMemory(pObA);
return 0;
}
转载于:https://www.cnblogs.com/19841111/archive/2010/08/20/1805043.html
Chapter10:观察者模式相关推荐
- Java设计模式:观察者模式
观察者模式 观察者模式又称为发布/订阅(Publish/Subscribe)模式 在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新. 如果这句话不好理解 可 ...
- 观察者模式的经典应用(猫叫 烧开水)
Code 猫叫了 老鼠跑 主人惊醒 1/**//* 2 * 题目: 3 * 猫叫了,所有老鼠开始逃跑,主人被惊醒,请用OO的思想描绘此过程 4 * 1,老鼠跟主人是被动的 5 * 2,要考虑 ...
- Observer Pattern 观察者模式
Observer Pattern (观察者模式) 定义: <设计模式>中对Observer模式的意图是这样描述的:"定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, ...
- 设计模式之观察者模式(Observer)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- java观察者模式_Java设计模式之观察者模式详解
观察者模式,是一对多的关系,一个主题对应多个观察者,当这个主题发生变化的时候,所有观察着这个主题的观察者都会接收到通知来获悉主题的变化. 在现实中我们也会遇到许许多多应用观察者模式的行为,比如电视的节 ...
- python 设计模式 观察者_python设计模式之观察者模式
说到观察者模式,在我脑海中总是闪现,这家伙跟消息队列的主题发布订阅有什么关系,虽然本人对消息队列没有很深的研究,但是凭直觉我就认为消息队列的实现就使用了观察者模式吧,所以本文就来模拟消息队列的丐版实现 ...
- JS设计模式-观察者模式
观察者(又称发布订阅)模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新. 原文链接 应用场景 当用户在网页执行一些操作(如点击)后就需要执行 ...
- 观察者模式(Observer Pattern)(二):HeadFirst中的气象站的实现
1 观察者模式的原理,首先由一个主题,当主题发送变化的时候,通知该主题的订阅者 按照上面的分析我们来进行设计 1.抽象主题Subject public interface Subject {publi ...
- 步步为营-44-窗体之间传值--观察者模式
说明 :观察者模式又叫发布-订阅模式,其中又涉及到中介者模式 1 结构 2 创建Main窗体(中介者),ChildForm1(发布者),ChildForm2(订阅者),ChildForm3(订阅者), ...
最新文章
- 问候Maven3(笔记一)
- mysql约束sex_MySQL笔记--约束
- Redis安装和使用指南
- 【转】ABP源码分析十二:本地化
- quartz各版本MySQL数据库存储建表SQL语句
- get和post的联系与区别
- 收起虚拟键盘的各种方法 -- IOS
- android支持平台,Android 平台功能
- 关于wxwidgets图形界面的关闭窗口的按钮无效的解决办法
- android之textview属性介绍
- 态路小课堂丨光缆知识
- 内网穿透干货教程,1分钟极速穿透内网端口
- CSDN日报20170612 ——《程序员,感觉技术停滞了怎么办?》
- Windows下C++调用系统软键盘及其需要注意的点
- 【Python基础】第十六篇 | 面向对象之高级篇
- Revit SDK EXTENSIONS(软件开发工具包扩展)是什么
- 【数据压缩】作业1-1:对浊音、清音、爆破音进行音频分析
- 佳博/芯桦打票机对接(含USB和网口)
- 华为android10手机指纹,华为P10这些指纹功能你知道几个?
- 如何用Python找出英语和汉语中特定词性的单词