首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

模板运用-观察者模式

2013-09-05 
模板应用--观察者模式介绍写不出介绍来,直接搜索,来自百度百科:观察者模式(有时又被称为发布-订阅Subscrib

模板应用--观察者模式
介绍
    写不出介绍来,直接搜索,来自百度百科:观察者模式(有时又被称为发布-订阅Subscribe>模式、模型-视图View>模式、源-收听者Listener>模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件(Subject)管理所有相依于它的观察者物件(Observer),并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。
    举个例子,用户界面上有柱状图、饼状图、历史记录表,他们都作为一个观察者,业务数据是被观察者(Subject),各显示区域观察业务数据的变化,发现数据变化后,就更新界面显示。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。


背景
    在我看来,面向对象编程方法主要目的就是解耦使其可维护、易扩展、可复用等,通过封装、继承、多态来实现,设计模式谈论更多的也是以组合、聚合或关联的解耦方式来达到这些目的,所以通常来说,代码的质量是高耦合<低耦合,低耦合<无耦合。
    关于观察者模式,网上有铺天盖地的原理分析、应用场景介绍、实例代码,不过大致都是一些基本思想,包括实例代码也仅仅是作为入门参考,具体应用到项目中还需考虑很多细节问题,往往这些细节问题决定了这个代码框架的可用性和可扩展性的程度。这其中就包括以下必须仔细思考的问题:
    1.一个Observer可否观察多个Subject?(别拿“一个类做一件事”来说事)
    2.对Subject进行更新时,可否选择随意的方式?比如更新一小部分和更新全部
    3.Observer收到数据通知时,可否有选择地感知/忽略数据更新发起者?可否感知/忽略数据更新前后的状态?
    4.抽象要到哪一级别?或者说哪些接口必须抽象出来?参数有哪些?
    5.如何界定达到了最低耦合度?是否可以做到“无耦合”?
    6.如何保证参与对象的生命周期?
    7.如何做到线程安全?在线程安全的前提下又如何保证不会出现竞态死锁?
    。。。。。。


实现
    针对上面提出的问题,一个一个来解决。
    1.一个Observer可否观察多个Subject?

    如果抽象出Observer和Subject作为基类,Subject要提供的外部接口包括update、register、unregister,内部接口有notify进行事件通知;Observer要提供data_changed接口供事件通知调用,为了让Observer可否观察多个具体的Subject对象,让所有数据类继承自Subject基类,然后这个Observer对象逐一调用各具体Subject的register接口注册自己成为观察者。貌似能解决第一个问题,可仔细想想,Observer只有一个data_changed接口,也就是说ConcreteObserver的data_changed实现只能是下面这个样子的:

#include <map>#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/foreach.hpp>#include <boost/thread.hpp>//////////////////////////////////////////////////////////////////////////template<class updater, class Data>struct subject_update_evt {updatersender_;Dataold_data_;Datanew_data_;};template <class Data, class Event>class subject : public boost::noncopyable{public:typedef boost::function<void (Event evt)>observer_obj;typedef Datadata_type;typedef Eventevt_type;typedefstd::map<int, observer_obj>observer_objs;typedef subject<Data, Event>this_type;typedef boost::function<bool (data_type&, evt_type*)>special_updater;typedef boost::recursive_mutexmutex;protected:/* ** the original data that need to be monitored*/data_typedata_;/* ** hold all of the observers that interest in data*/observer_objsobservers_;//! mutexmtx_;//!boolchanging_;struct scope_state_reverse{bool&state_;scope_state_reverse(bool& state):state_(state){assert(!state_);state_ = !state_;}~scope_state_reverse(){state_ = !state_;}};/* ** notify all observers that the data has changed*/voidnotify(observer_objs& objs, Event evt){for(observer_objs::iterator it = objs.begin(); it != objs.end(); ++it){try{it->second(evt);}catch(...){}}}private:/* ** standard constructor, must be hidden from outside*/subject():changing_(false){}public:boost::shared_ptr<this_type> Create(){return new boost::shared_ptr<this_type>(this_type);}/*** get the data (thread safe)** this method will make a copy of source data and reset to parameter dt** return true if the parameter dt is reset*/boolget_data(this_type::data_type& dt){boost::unique_lock<mutex> guard(mtx_);if (!guard)return false;dt = data_;return true;}/*** access the data (thread safe)** this method only pass the source data to the accessor functor.** the accessor functor must has the signature of accepting a Data type parameter*/template<class accessor>voidaccessed_by(accessor acc){boost::unique_lock<mutex> guard(mtx_);if (!guard)return;const typename this_type::data_type& replacement = data_;acc(replacement);}/* ** register a observer** the parameter 'obs' must be a functor that can call observer's data_changed function** return true means register successfully*/boolregister_obs(void* ptr, const typename this_type::observer_obj& obs){// maybe block hereboost::unique_lock<mutex> guard(mtx_);if (guard){if (changing_)return false;observer_objs::iterator it = observers_.find(ptr);if (it == observers_.end()){observers_[ptr] = obs;return true;}}return false;}/* ** unregister a observer** the parameter 'ptr' is the data_changed receiver object that registered.*/boolunregister_obs(int key){// maybe block hereboost::unique_lock<mutex> guard(mtx_);if (guard){if (changing_)return false;observer_objs::iterator it = observers_.find(key);if (it != observers_.end()){observers_.erase(it);return true;}}return false;}/* ** full update the data and notify observers*/boolupdate(const Data& data, Event evt){// maybe block hereboost::unique_lock<mutex> guard(mtx_);if (!guard || changing_)return false;scope_state_reverse ssr(changing_);data_ = data;notify(observers_, evt);return true;}/* ** customize update method and notify observers after that*/boolupdate(special_updater op){// maybe block hereboost::unique_lock<mutex> guard(mtx_);if (!guard || changing_)return false;scope_state_reverse ssr(changing_);Event evt;if (op(data_, &evt)){notify(observers_, evt);return true;}return false;}};



热点排行