观察者模式(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=孟栋

多加点评!谢谢

最新文章

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

热门文章

  1. BluetoothGetRadioInfo 函数
  2. [解决问题]ubuntu无法virtualenv创建python虚拟环境的解决
  3. [51nod1267]4个数和为0(预处理+双指针)
  4. [poj2104]可持久化线段树入门题(主席树)
  5. GC算法与种类
  6. jmeter响应结果乱码问题
  7. linux学习第一周小结
  8. C#----接口与多继承
  9. 从CGI到FastCGI到PHP-FPM
  10. Exceptionless - .Net Core开源日志框架