设计模式--观察者模式(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=孟栋
多加点评!谢谢
最新文章
- 实践 HTML5 的 CSS3 Media Queries
- FOOD
- [实战经验]Macbook pro 苹果系统换window系统
- memcpy、memmove、memset及strcpy函数实现和理解
- 设置BootStrap导航条的高度
- 在fragment中获取他附着的activity中的变量
- zzuli oj 1134 字符串转换
- linux命令学习汇总
- H3C无线路由器安装与设置
- 阿里云或本地部署服务器(一)---nginx本地和服务器代理
- https认证握手过程
- smartctl 检测磁盘信息
- vue+窗格切换+田字+dicom显示_03
- 约束 CONSTRAINT
- 键&#39;attachdbfilename&#39;的值无效。
- Linux 网络流量实时监控工具之ntopng详解
- 【React Native开发】React Native应用设备执行(Running)以及调试(Debugging)(3)
- 掌握所有编程语言不是梦-转自csdn
- 微信小程序:工具配置 project.config.json
- php萌新|学习|排坑|のmysqli_error()方法的妙用