zoukankan      html  css  js  c++  java
  • 设计模式之观察者模式

      观察者模式又称发布-订阅模式,是一种行为型模式。在此种模式中,一个目标物件管理所有相依于它的观察者物件,

      并且在它本身的状态改变时主动发出通知。这种模式通常用来实现事件处理系统。

      观察者模式完美的将观察者和被观察的对象分离开,在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

      观察者模式定义了对象间的一种一对多的依赖关系,以便一个对象状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

    实现方式: 

      观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。实现的时候要注意,

        观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,

        从根本上违反面向对象的设计的原则。无论是观察者“观察”被观察对象,还是被观察对象将自己的改变“通知”观察者,都不应该直接调用。

      比较直观的一种是“注册-通知-撤销注册"的形式。

      

    观察者(Observer)将自己注册到被观察对象(Subject),被观察对象将观察者存放在一个容器里,被观察对象发生了某种变化,

      从容器中得到所有注册过的观察者,将变化通知观察者。观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

      观察者将自己注册到被观察者的容器中,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:

      假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,

      它可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现

    观察者模式的适用场景就是一个类发生变化,需要将消息传递到相关很多类的时候。

      1 #include<iostream>
      2 #include<set>
      3 #include<string>
      4 using namespace std;
      5 /////////////////////抽象模式定义
      6 class CObservable;
      7 //观察者,纯虚基类
      8 class CObserver
      9 {
     10 public:
     11 CObserver::CObserver(){};
     12 virtual CObserver::~CObserver(){};
     13 //当被观察的目标发生变化时,通知调用该方法
     14 //来自被观察者pObs,扩展参数为pArg
     15 virtual void Update(CObservable*pObs,void*pArg=NULL)=0;
     16 };
     17 //被观察者,即Subject
     18 class CObservable
     19 {
     20 public:
     21 CObservable():m_bChanged(false){};
     22 virtual~CObservable(){};
     23 //注册观察者
     24 void Attach(CObserver*pObs);
     25 //注销观察者
     26 void Detach(CObserver*pObs);
     27 //注销所有观察者
     28 void DetachAll();
     29 //若状态变化,则遍历观察者,逐个通知更新
     30 void Notify(void*pArg=NULL);
     31 //测试目标状态是否变化
     32 bool HasChanged();
     33 //获取观察者数量
     34 int GetObserversCount();
     35 protected:
     36 //设置状态变化!!!必须继承CObservable才能设置目标状态
     37 void SetChanged();
     38 //初始化目标为未变化状态
     39 void ClearChanged();
     40 private:
     41 boolm_bChanged;//状态
     42 set<CObserver*>m_setObs;//set保证目标唯一性
     43 };
     44 /////////////////////抽象模式实现
     45 void CObservable::Attach(CObserver*pObs)
     46 {
     47 if(!pObs)return;
     48 m_setObs.insert(pObs);
     49 }
     50 void CObservable::Detach(CObserver*pObs)
     51 {
     52 if(!pObs)return;
     53 m_setObs.erase(pObs);
     54 }
     55 void CObservable::DetachAll()
     56 {
     57 m_setObs.clear();
     58 }
     59 void CObservable::SetChanged()
     60 {
     61 m_bChanged=true;
     62 }
     63 void CObservable::ClearChanged()
     64 {
     65 m_bChanged=false;
     66 }
     67 bool CObservable::HasChanged()
     68 {
     69 returnm_bChanged;
     70 }
     71 int CObservable::GetObserversCount()
     72 {
     73 returnm_setObs.size();
     74 }
     75 void CObservable::Notify(void*pArg/*=NULL*/)
     76 {
     77 if(!HasChanged())return;
     78 cout<<"notifyobservers…"<<endl;
     79 ClearChanged();
     80 set<CObserver*>::iteratoritr=m_setObs.begin();
     81 for(;itr!=m_setObs.end();itr++)
     82 {
     83 (*itr)->Update(this,pArg);
     84 }
     85 }
     86 /////////////////////具体应用类定义和实现
     87 //bloger是发布者,即被观察者(subject)
     88 class CBloger:public CObservable
     89 {
     90 public:
     91 void Publish(conststring&strContent)
     92 {
     93 cout<<"blogerpublish,content:"<<strContent<<endl;
     94 SetChanged();
     95 Notify(const_cast<char*>(strContent.c_str()));
     96 }
     97 };
     98 //portal是发布者,即被观察者(subject)
     99 class CPortal:public CObservable
    100 {
    101 public:
    102 void Publish(const string &strContent)
    103 {
    104 cout<<"portalpublish,content:"<<strContent<<endl;
    105 SetChanged();
    106 Notify(const_cast<char*>(strContent.c_str()));
    107 }
    108 };
    109 //RSS阅读器,观察者
    110 class CRSSReader:public CObserver
    111 {
    112 public:
    113 CRSSReader(conststring&strName):m_strName(strName){}
    114 virtual void Update(CObservable *pObs,void *pArg=NULL)
    115 {
    116 char *pContent=static_cast<char*>(pArg);
    117 //观察多个目标
    118 if(dynamic_cast<CBloger*>(pObs))
    119 {
    120 cout<<m_strName<<"updated from bloger,content:"<<pContent<<endl;
    121 }
    122 elseif(dynamic_cast<CPortal*>(pObs))
    123 {
    124 cout<<m_strName<<"updated from portal,content:"<<pContent<<endl;
    125 }
    126 }
    127 private:
    128 stringm_strName;
    129 };
    130 //Mail阅读器,观察者
    131 class CMailReader:public CObserver
    132 {
    133 public:
    134 CMailReader(conststring &strName):m_strName(strName){}
    135 virtual void Update(CObservable *pObs,void *pArg=NULL)
    136 {
    137 char *pContent=static_cast<char*>(pArg);
    138 if(dynamic_cast<CBloger*>(pObs))
    139 {
    140 cout<<m_strName<<"updated from bloger,content:"<<pContent<<endl;
    141 }
    142 if(dynamic_cast<CPortal*>(pObs))
    143 {
    144 cout<<m_strName<<"updated from portal,content:"<<pContent<<endl;
    145 }
    146 }
    147 private:
    148 stringm_strName;
    149 };
    150 /////////////////Main
    151 intmain()
    152 {
    153 //目标(被观察者)
    154 CBloger *pBloger=newCBloger();
    155 CPortal *pPortal=newCPortal();
    156 //观察者.一个观察者可以观察多个目标
    157 CRSSReader *pRssReader=new CRSSReader("rssreader");
    158 CMailReader *pMailReader=new CMailReader("mailreader");
    159 pBloger->Attach(pRssReader);//bloger注册观察者
    160 pBloger->Attach(pMailReader);//bloger注册观察者
    161 pPortal->Attach(pRssReader);//portal注册观察者
    162 pPortal->Attach(pMailReader);//portal注册观察者
    163 //博客发布信息
    164 pBloger->Publish("博客分享设计模式");
    165 cout<<endl;
    166 //门户发布信息
    167 pPortal->Publish("门户分享设计模式");
    168 cout<<"
    portaldetachedmailreader"<<endl;
    169 pPortal->Detach(pMailReader);
    170 cout<<"portalobserverscount:"<<pPortal->GetObserversCount()<<endl<<endl;
    171 pPortal->Publish("门户分享设计模式");
    172 system("pause");
    173 return0;
    174 }
  • 相关阅读:
    轻节点如何验证交易的存在
    梯度爆炸/消失与初始化参数
    归一化能够加速训练的原因
    正则化可以防止过拟合的原因
    关于周志华《机器学习》中假设空间规模大小65的计算
    linux学习0001
    目标检测算法
    opencv安装与卸载
    前端学习02
    前端学习01
  • 原文地址:https://www.cnblogs.com/qianqiannian/p/6965083.html
Copyright © 2011-2022 走看看