C++设计模式新解四 观察者模式+事件订阅
来源:互联网 发布:国际数据公司 收购 编辑:程序博客网 时间:2024/05/21 06:33
定义:定义对象间的一种一对多关系的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式又被称为发布/订阅模式,在这种模式中,一个目标物件(被观察者)管理所有相依于它的相关物件(观察者),并且在目标物件的状态发生改变时主动发出通知。这通常通过各物件所提供的方法来实现,观察者模式通常被用来做事件处理系统。
举个例子:老板就是被观察者,员工就是观察者,大家都看着老板的指挥行动,让你往东你就往东,让你往西你就往西,员工在老板处留下了不同的联系方式有Email,电话,手机,QQ,微信等,一旦老板做了决定就会主动通过不同的方式通知到大家。
再举个例子:用户界面是观察者,业务数据可以作为被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在用户界面上。
至少需要两个角色:观察者类和被观察者类。
在实现观察者模式的多种形式中,比较直观的是一种“注册----通知----撤销注册”的形式。
注册:在被观察者对象中,放置一个容器保存相关的观察者对象。
通知:一旦被观察对象中的状态发生变化,则通知容器中所有的观察者对象做出相应变化。
撤销注册:将被观察者对象容器中某个要撤销的观察者对象删除。
实际上这种实现方式不仅要包含被观察者和观察者类。因为观察者对象要把自己注册到被观察者对象容器中,被观察者不应该过问观察者的具体类型,而应该使用观察者提供的接口。优点是,假定还有别的观察者,那么只要这个观察者也是相同的接口实现即可。基于接口而不是具体实现,为程序提供了强大的灵活性。也就是说要包含所有观察者的基类。
以下为ObserveDesign.h的源代码
#include <map>#include <list>#include <windows.h>#include <iostream>#include <string>#include "stdafx.h"using namespace std;typedef enum {Event_Invalid = 0,Event_Login = 1,Event_Logout = 2,}EVENT_ID;//观察的事件struct MyEvent{EVENT_ID mEventId;UINT mUniqueIndex;MyEvent(EVENT_ID eventId, UINT uniqueIndex):mEventId(eventId),mUniqueIndex(uniqueIndex){}bool operator == (const MyEvent & rhs){return mEventId == rhs.mEventId;}bool operator < (const MyEvent & rhs) const;};struct LoginEvent: public MyEvent{public:LoginEvent(EVENT_ID eventId, UINT uniqueIndex):MyEvent(eventId, uniqueIndex){}};struct LogoutEvent: public MyEvent{public:LogoutEvent(EVENT_ID eventId, UINT uniqueIndex):MyEvent(eventId, uniqueIndex){}};struct MyEntity;struct EventEngine{public:void Attach(MyEvent pEvent, MyEntity * pEntity);void Detach(MyEvent pEvent);void DetachAll();void fire(MyEvent pEvent);private:typedef std::list<MyEntity*> EventList; //单个时间的订阅者列表typedef std::map<EVENT_ID, EventList> EventListMap; //多个事件的订阅者列表,结构体作为Keytypedef EventList::iterator EventListIter;typedef EventListMap::iterator EventListMapIter;EventListMap m_map;static EventEngine * mInstance;EventEngine(){}public:static EventEngine * getInstance(){if(mInstance == NULL){mInstance = new EventEngine();}return mInstance;}};void fireEvent(MyEvent pEvent){EventEngine::getInstance()->fire(pEvent);}EventEngine * EventEngine::mInstance = NULL;//观察者(建立该类的虚函数是为了让继承自它的类具体实现该虚函数,以便于在事件管理器的代码编写,事件触发时,直接调用CallBack()函数)struct MyEntity{public:MyEntity(int pId):mId(pId){}virtual void CallBack() = 0;void subscribe(MyEvent pEvent){EventEngine::getInstance()->Attach(pEvent, this);}void unSubscribe(MyEvent pEvent){EventEngine::getInstance()->Detach(pEvent);}int getId(){return mId;}private:int mId;};//英雄struct Hero: public MyEntity{public:Hero(int pId):MyEntity(pId){}void CallBack(){cout << "Hero " << getId() << " CallBack" << endl;};};//怪物struct Monster: public MyEntity{public:Monster(int pId):MyEntity(pId){}void CallBack(){cout << "Monster " << getId() << " CallBack" << endl;};};
以下为ObserveDesign.cpp的源代码
#include "ObserveDesign.h"bool MyEvent::operator < (const MyEvent & rhs) const{return mEventId < rhs.mEventId;}void EventEngine::Attach(MyEvent pEvent, MyEntity * pEntity){EventListMap::iterator iter = m_map.find(pEvent.mEventId);if(iter == m_map.end()){std::list<MyEntity*> entityList;entityList.push_front(pEntity);m_map.insert(EventListMap::value_type(pEvent.mEventId, entityList));}else{(iter->second).push_front(pEntity);}}void EventEngine::Detach(MyEvent pEvent){if(m_map.empty())return;EventListMap::iterator mIter = m_map.find(pEvent.mEventId);if(mIter != m_map.end()){EventListIter lIter = (mIter->second).begin();for(; lIter != (mIter->second).end(); ++lIter){if((*lIter)->getId() == pEvent.mUniqueIndex){(mIter->second).erase(lIter);return;}}}}void EventEngine::DetachAll(){EventListMapIter mIter = m_map.begin();for(; mIter != m_map.end(); ++mIter ){mIter->second.clear();}m_map.clear();}void EventEngine::fire(MyEvent pEvent){EventListMapIter mIter = m_map.find(pEvent.mEventId);if(mIter == m_map.end())return;EventListIter lIter = (mIter->second).begin();for(; lIter != (mIter->second).end(); ++lIter){if((*lIter)->getId() == pEvent.mUniqueIndex){(*lIter)->CallBack();return;}}}int main(){Hero * h1 = new Hero(1);Hero * h2 = new Hero(2);Monster * m1 = new Monster(3);Monster * m2 = new Monster(4);LoginEvent l1(Event_Login, h1->getId());LoginEvent l2(Event_Logout, h1->getId());LogoutEvent l3(Event_Login, m1->getId());LogoutEvent l4(Event_Logout, m2->getId());h1->subscribe(l1);h1->subscribe(l2);m1->subscribe(l3);m1->subscribe(l4);fireEvent(l1);fireEvent(l3);system("pause");return 0;}
这里做了以下几个小改动。
1.将所有的观察者与被观察者放在一个EventEngine管理类统一管理。
2.全部观察者继承同一个接口,便于管理。
PS,本例中观察者为MyEntity以及实现该接口的全部子类,
被观察者为MyEvent以及实现该接口的全部子类。
EventEngine使用单例模式统一管理全部的注册事件的对象。EventEngine采用的容器是以Event事件ID作为Key,订阅该事件的全部观察者对象的list作为Value的map。
list是当订阅相同事件的对象注册事件时,直接把该对象插入list就可以了。
我们的采用EventId以及对象的Id联合的方式作为订阅该事件的对象的订阅标准。
既可以区分开不同的事件,也可以区分开不同的订阅该事件的订阅者。
全部的代码就是为了 fireEvent这一瞬间做准备。
如果还有什么疑问,最好自己写一遍代码,一切清楚。
- C++设计模式新解四 观察者模式+事件订阅
- java设计模式-观察者(发布-订阅)模式
- 初识c#---委托,事件和观察者模式(Observer)设计模式
- 十六 设计模式之观察者模式(发布订阅模式)
- PHP设计模式-观察者模式(订阅者模式)
- 监听器设计模式(观察者模式、订阅发布模式)
- PHP设计模式-观察者模式(订阅者模式)
- 设计模式之观察者模式(发布-订阅模式)
- 设计模式之观察者模式(订阅模式),jquery实现
- [设计模式] 观察者模式(发布-订阅/Publish-subscribe模式)
- 我理解的设计模式:观察者模式(订阅发布模式)
- PHP设计模式-观察者模式(订阅者模式)
- Javascript设计模式-07-观察者模式(发布订阅模式)
- 设计模式二:观察者模式(发布订阅模式)
- java笔记--设计模式之观察者(订阅/发布)模式
- 设计模式(三)观察者模式Observer(发布订阅)
- java设计模式-观察者模式(广播机制,消息订阅)
- 浅析JavaScript设计模式——发布-订阅/观察者模式
- JQ的学习
- [Servlet&JSP] 过滤器的使用
- 【我的JS第三本】JavaScript_DOM编程艺术第二版读书笔记
- 清空mysql 查询缓存
- HDU 1178 Heritage from father 数学公式 JAVA
- C++设计模式新解四 观察者模式+事件订阅
- 以太网帧格式
- android-文字的处理(最后一条 不用setCompoundDrawables 在text上加图片)
- C++中类成员函数作为回调函数
- 三个容易混淆的jquery选择器
- 网格的学习—2
- Android内存泄露总结(一)
- linux 进程管理
- 二叉排序树(BST)