设计模式--观察者模式(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种解决方式,但在面向对象的设计中如何能做到“高内聚,低 ...
随机推荐
- 将List中部分字段转换为DataTable中
由于原来方法导出数据量比较大 的时候,出现卡顿现象:搜索简单改造:(下面方法借助NPIO) /// <summary> /// 将List中原文和译文转换为Datatable /// &l ...
- IIS7.0(虚拟机)发布MVC5程序出现Http403错误的解决方法.
近来,用MVC5开发自己的一个小网站.网上租用了一个小空间(虚拟主机),可选.net版本为2.0 3.0 3.5 4.0 ,上传网站 后发现是403错误.不能访问. 经与技术人员联系,把虚拟机更换到高 ...
- [hdu2159]FATE二维多重背包(背包九讲练习)
解题关键:二维约束条件,只需加一维状态即可. 转移方程:$f[j][k] = \max (f[j][k],f[j - w[i]][k - 1] + v[i])$ #include<bits/st ...
- Lua中的点、冒号与self
Lua中的点.冒号与self,它们之间的关系主要体现在函数的定义与调用上,Lua在函数定义时可以用点也可以用冒号,如: function mytable.fun(p) return p end fun ...
- linux 安装输入法
简述 Ubuntu16.04安装完后,和12.04以及14.04都不一样,并没有中文输入功能.于是搜索一些安装中文输入法的方法. 开始安装了ibus pinyin输入法,但是系统重启之后发现有些时候不 ...
- 3、Linux下配置Java环境
转载:http://blog.sina.com.cn/s/blog_c5a35e780102wtxl.html 生物信息很多软件都是用java写的,所以需要在linux上配置java运行环境.平台上的 ...
- miRNA
MicroRNA (miRNA) 是一类内生的.长度约为20-24个核苷酸的小 RNA,其在细胞内具有多种重要的调节作用.每个 miRNA 可以有多个靶基因的表达,而几个 miRNA 也可以调节同一 ...
- 阶段3-团队合作\项目-网络安全传输系统\sprint3-账号管理子系统设计\第2课-账号管理子系统设计
账号管理子系统的设计 客户端需要登录到服务器,在服务器去查询数据库,进行验证该用户. 打开client.c文件 编译之 把它复制到开发板里面去 这个程序是在本地数据库测试的!!!!!!!!!!!!!! ...
- 8.bwapp亲测xxe漏洞
这几天在学习XXE漏洞,这里用靶机bwapp来练习一下这个漏洞,重在学习 xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤, 从而可以造成命令执行,目录遍历 ...
- setTimeout关于函数名做参数的问题
前几天在调bug时发现一个诡异的问题. function test(){ alert('4 seconds!'); } setTimeout(test(),4000); 这段代码立即执行,当时看不出问 ...