观察者模式(Observer):观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

  举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。

  观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。

  观察者

  观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。

  被观察者

  被观察者(subject)发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。

  

C++实现demo。

游戏中玩家数据和界面玩家UI之间必然会有关联,当玩家数据变化后,响应的UI也应该及时更新。

两个虚基类:AbsSubject(被观察者),AbsObserver(观察者);    被观察者实现类:User(玩家数据类);

观察者实现类:UserView(玩家信息面板类);HallView(大厅信息面板类)

玩家信息面板和大厅信息面板都包含玩家昵称(name)和金币值(gold),当玩家金币值发生变化后,玩家(User)通知面板(UserView和HallView)也应发生响应变化。

AbsSubject.h(被观察者):

 class AbsObserver;
//被观察者,虚基类
class AbsSubject
{
public:
//ctor
AbsSubject():m_bChanged(false) {};
//pure dtor
virtual ~AbsSubject() { removeAllObserver(); };
//注册观察者
void addObserver(AbsObserver* obser);
//注销观察者
void removeObserver(AbsObserver* obser);
//注销所有观察者
void removeAllObserver();
//向所有观察者发送通知
void postNotification(void*arg = NULL); //get observer count
int getObserverCount() { return m_setObser.size(); }
//状态是否变化
bool hasChanged() { return m_bChanged; };
//set changed true
void setChanged() { m_bChanged = true; }
//clear changed
void clearChanged() { m_bChanged = false; } private:
bool m_bChanged;//是否变化
set<AbsObserver*> m_setObser;//观察者集合,set保证对象唯一
};

AbsSubject.cpp(被观察者):

 #include "stdafx.h"
#include "AbsSubject.h" void AbsSubject::addObserver(AbsObserver * obser)
{
if (!obser)return;
m_setObser.insert(obser);
} void AbsSubject::removeObserver(AbsObserver * obser)
{
if (!obser)return;
m_setObser.erase(obser);
} void AbsSubject::removeAllObserver()
{
m_setObser.clear();
} void AbsSubject::postNotification(void * arg)
{
if (!hasChanged())return;
clearChanged();
if (getObserverCount() == )return;//safe check set<AbsObserver*>::iterator itor = m_setObser.begin();
do
{
(*itor)->update(this, arg);
itor++;
} while (itor != m_setObser.end()); }

AbsObserver(观察者):

 class AbsSubject;
//观察者基类,纯虚基类
class AbsObserver
{
public:
//ctor
AbsObserver() {};
//dtor
virtual ~AbsObserver() {};
//pure virtual function.
//当被观察者(subject)发生变化时,通知调用该方法
virtual void update(AbsSubject* subject, void* arg) = ; };

被观察者实现类:User(玩家数据类)

 #pragma once

 //玩家数据,被观察者
class User:public AbsSubject
{
public:
//ctor
User(string name);
//dtor
~User(); //增加gold
void addGold(int gold); //广播通知
void post(const string& content); public:
//get name
string getName() { return m_strName; }
//get gold;
int getGold() { return m_iGold; } private:
string m_strName;//昵称
int m_iGold;//金币 }; User::User(string name)
:m_strName(name),
m_iGold()
{
} User::~User()
{
} void User::addGold(int gold)
{
if (gold == )return;
m_iGold += gold;
m_iGold = m_iGold < ? : m_iGold;//safe check post(m_strName);
} void User::post(const string & content)
{
setChanged();
postNotification(const_cast<char*>(content.c_str())); }

观察者实现类:UserView(玩家信息面板类):

 #pragma once

 //玩家界面,观察者
class UserView:public AbsObserver
{
public:
//ctor
UserView(User* user) :m_user(user){ user->addObserver(this); }
//dtor
~UserView() { m_user->removeObserver(this); }
//当被观察者(subject)发生变化时,通知调用该方法
virtual void update(AbsSubject* subject, void* arg); private:
//string m_strName;//user name
User* m_user;//user
}; void UserView::update(AbsSubject * subject, void * arg)
{
char* content = static_cast<char*>(arg);
if (dynamic_cast<User*>(subject))
{
cout << "UserView::update From User=" << m_user->getName() << ",gold=" << m_user->getGold() << ",Arg=" << content << endl;
}
else
{
cout << "UserView::update From XXX=" << m_user->getName() << ",gold=" << m_user->getGold() << ",Arg=" << content << endl;
}
}

HallView(大厅信息面板类):

 #pragma once
//大厅界面,观察者
class HallView:public AbsObserver
{
public:
//ctor
HallView(User* user):m_user(user) { user->addObserver(this); }
//dtor
~HallView() { m_user->removeObserver(this); };
//当被观察者(subject)发生变化时,通知调用该方法
virtual void update(AbsSubject* subject, void* arg); private:
User* m_user;//玩家 }; void HallView::update(AbsSubject * subject, void * arg)
{
char* content = static_cast<char*>(arg);
if (dynamic_cast<User*>(subject))
{
cout << "HallView::update From User="<<m_user->getName()<<",gold=" << m_user->getGold()<<",arg="<<content<< endl;
}
else
{
cout << "HallView::update From XXX=" << m_user->getName() << ",gold=" << m_user->getGold()<<",arg=" << content << endl;
}
}

main()测试:

 int main()
{
//玩家(被观察者)
User* user = new User("孟栋"); //玩家面板(观察者1)
UserView* userView = new UserView(user);
//大厅面板(观察者2)
HallView* hallView = new HallView(user); //玩家增加50金币,玩家面板和大厅面板会更新玩家UI信息
user->addGold(); //玩家减少30金币,玩家面板和大厅面板会更新玩家UI信息
user->addGold(-); return ;
}

打印:

UserView::update From User=孟栋,gold=,Arg=孟栋
HallView::update From User=孟栋,gold=,arg=孟栋
UserView::update From User=孟栋,gold=,Arg=孟栋
HallView::update From User=孟栋,gold=,arg=孟栋

多加点评!谢谢

设计模式--观察者模式(KVO)的更多相关文章

  1. 18. 星际争霸之php设计模式--观察者模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  2. linkin大话设计模式--观察者模式

    linkin大话设计模式--观察者模式 观察者模式定义了对象间的一对多依赖关系,让一个或者多个观察者观察一个对象主题.当主题对象的状态发生改变的时候,系统能通知所有的依赖于此对象的观察者对象,从而能自 ...

  3. java设计模式--观察者模式(Observer)

    java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...

  4. js设计模式-观察者模式

    定义: 观察者模式又叫发布订阅模式,它定义了对象间的一种一对多的依赖关系.观察者模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响他们之间的互相通信. 思路 定义一个对象,在对象中实 ...

  5. 【设计模式】Java设计模式 - 观察者模式

    [设计模式]Java设计模式 - 观察者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 @一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长 ...

  6. IOS设计模式-观察者模式

    前言:23种软件设计模式中的观察者模式,也是在软件开发中,挺常用的一种设计模式.而在苹果开发中,苹果Cocoa框架已经给我们实现了这个设 计模式,那就是通知和KVO(Key-Value Observi ...

  7. [Head First设计模式]山西面馆中的设计模式——观察者模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 引言 不知不自觉又将设计模式融入生活了,吃个饭也不得安生,也发现生活中的很多场景,都可以用设计模式来模拟.原来设计模式就在 ...

  8. javascript 设计模式-----观察者模式

    观察者模式在设计模式中被重点提到,因为它应用的场景非常多,而且在模块化设计当中扮演着非常重要的角色.MVC模式中最底层的就是观察者模式,当下流行的javascript框架backbone就是很好地运用 ...

  9. c#设计模式-观察者模式

    Observer 与 Subject 互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体. 一.观察者模式 目的 我们都知道解决一个问题有N种解决方式,但在面向对象的设计中如何能做到“高内聚,低 ...

随机推荐

  1. CSS3新增的伪类

    Element1 ~ element2:选择前面有element1的所有element2元素 [attr ^= val] 属性值以val开头的元素 [attr $= val] 属性值以val结尾的元素 ...

  2. SQL一对多特殊查询,取唯一一条

    主表: 辅表: 一个app对应多个apk,现在要取上线(Apk_Status最大的)的应用 select * from [dbo].[tbl_APP] as app join ( * from tbl ...

  3. spring----IOC注解方式以及AOP

    技术分析之Spring框架的IOC功能之注解的方式 Spring框架的IOC之注解方式的快速入门 1. 步骤一:导入注解开发所有需要的jar包 * 引入IOC容器必须的6个jar包 * 多引入一个:S ...

  4. Python通过调用windows命令行处理sam文件

    Python通过调用windows命令行处理sam文件 以samtools软件为例 一.下载或者索取得到windows版本的samtools软件,解压后如下: 进入文件内部,有如下几个文件: 二.将s ...

  5. 6.(转载)SSRF漏洞挖掘经验

    SSRF 漏洞的寻找 一.从WEB功能上寻找 我们从上面的概述可以看出,SSRF是由于服务端获取其他服务器的相关信息的功能中形成的,因此我们大可以 列举几种在web 应用中常见的从服务端获取其他服务器 ...

  6. 关于vs2012解决方案中项目DLL文件引用问题

    今天用vs2012建了项目框架,老是出现说解决方案中的项目dll文件不存在,但是我按照路径去找是可以找到这个文件的,也就是说这个文件存在的.我按照引用顺序单个编译每个项目都是成功的,就是当我编译整个解 ...

  7. .net core 深入了解配置文件加载过程

    前言     配置文件中程序运行中,担当着不可或缺的角色:通常情况下,使用 visual studio 进行创建项目过程中,项目配置文件会自动生成在项目根目录下,如 appsettings.json, ...

  8. java学习笔记——基于Robot类的屏幕分享

    直接上代码,具体看注释: package robot; import java.awt.AWTException; import java.awt.Dimension; import java.awt ...

  9. 2017-10-24 NOIP模拟赛

    括号序列 (bracket) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法 ...

  10. LCA 【bzoj1787】[Ahoi2008]Meet 紧急集合

    LCA [bzoj1787][Ahoi2008]Meet 紧急集合 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1787 注意到边权为一 ...