设计模式--观察者模式(KVO)
观察者模式(Observer):观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。
观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。
观察者
被观察者
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)的更多相关文章
- 18. 星际争霸之php设计模式--观察者模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- linkin大话设计模式--观察者模式
linkin大话设计模式--观察者模式 观察者模式定义了对象间的一对多依赖关系,让一个或者多个观察者观察一个对象主题.当主题对象的状态发生改变的时候,系统能通知所有的依赖于此对象的观察者对象,从而能自 ...
- java设计模式--观察者模式(Observer)
java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...
- js设计模式-观察者模式
定义: 观察者模式又叫发布订阅模式,它定义了对象间的一种一对多的依赖关系.观察者模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响他们之间的互相通信. 思路 定义一个对象,在对象中实 ...
- 【设计模式】Java设计模式 - 观察者模式
[设计模式]Java设计模式 - 观察者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 @一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长 ...
- IOS设计模式-观察者模式
前言:23种软件设计模式中的观察者模式,也是在软件开发中,挺常用的一种设计模式.而在苹果开发中,苹果Cocoa框架已经给我们实现了这个设 计模式,那就是通知和KVO(Key-Value Observi ...
- [Head First设计模式]山西面馆中的设计模式——观察者模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 引言 不知不自觉又将设计模式融入生活了,吃个饭也不得安生,也发现生活中的很多场景,都可以用设计模式来模拟.原来设计模式就在 ...
- javascript 设计模式-----观察者模式
观察者模式在设计模式中被重点提到,因为它应用的场景非常多,而且在模块化设计当中扮演着非常重要的角色.MVC模式中最底层的就是观察者模式,当下流行的javascript框架backbone就是很好地运用 ...
- c#设计模式-观察者模式
Observer 与 Subject 互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体. 一.观察者模式 目的 我们都知道解决一个问题有N种解决方式,但在面向对象的设计中如何能做到“高内聚,低 ...
随机推荐
- ABCD四个人说真话的概率都是1/3。假如A声称B否认C说D是说谎了,那么D说过的那句话真话的概率是多少
ABCD四个人说真话的概率都是1/3.假如A声称B否认C说D是说谎了,那么D说过的那句话 真话的概率是多少 记"A声称B否认C说D说谎"为X,那么由贝叶斯公式,所求的 P(D真)P ...
- Windchill 配置LOG文件,使开发中的代码能显示打印的信息
如开发代码的类HomeLogic.java, 包路径在pnt.report.home 需求:需监控此类的打印数据 方法:配置D:\ptc\Windchill_10.1\Windchill\codeba ...
- android中如何在系统启动的时候启动自己的service
自定义一个broadcastreciver在去接受系统启动消息,然后在处理的时候启动自己的service即可
- Dexdump 无法正常反编译问题
WIN环境下无法正常运行,提示Unable open XXX as zip 解决方案:使用APKTOOL + JD-GUI进行替代反编译
- Maven 命令格式及一些常用命令
Maven自身指定定义了一套对项目进行编译,测试,打包,运行,部署等工作的抽象.Maven自己是不实际负责这些工作的,而是把它们交给了插件.所以Maven命令的实际工作执行者是各种各样的插件. 要了解 ...
- Gulp的学习和使用
Gulp是一种直观.自动化构建的工具. Gulp是基于Node和NPM,安装教程点这里. 什么是Gulp? Gulp使用了node.js的流控制系统,使其(Gulp)构建更快,因为它不需要将临时文件/ ...
- 【转】如何在eclipse下配置Heritrix
如何配置在eclipse下配置Heritrix 在其他帖子上看到有Eclipse 配置 Heritrix 1.14.4的文章,这里有很多内容是引用自那里.如http://extjs2.javaeye. ...
- The project was not built since its build path is incomplete. Cannot find the class file for java.lang.Object
The project was not built since its build path is incomplete. Cannot find the class file for java.la ...
- 关于vs2012解决方案中项目DLL文件引用问题
今天用vs2012建了项目框架,老是出现说解决方案中的项目dll文件不存在,但是我按照路径去找是可以找到这个文件的,也就是说这个文件存在的.我按照引用顺序单个编译每个项目都是成功的,就是当我编译整个解 ...
- Linux中常用压缩命令
.zip格式压缩 zip 压缩文件名 源文件 压缩文件 zip -r 压缩文件名 源目录 压缩目录 .zip格式解压缩 unzip 压缩文件 解压.zip文件 .gz格式压缩 gzip 源文件 压缩为 ...