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

    Observer模式应该可以说是应用最多、影响最广的模式之一,因为Observer的一个实例Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义,MVC实现了业务逻辑和表现层的解耦。Observer模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者

    最常见的一个例子:对同一组数据进行统计分析时,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们需要当数据改变的时候,所有的统计显示都能够同时改变。Observer模式就是解决这一问题。

    UML类图

    Subject(目标)
    ——目标知道它的观察者。可以有任意多个观察者观察同一个目标;
    ——提供注册和删除观察者对象的接口。

    Observer(观察者)
    ——为那些在目标发生改变时需获得通知的对象定义一个更新接口。

    ConcreteSubject(具体目标)
    ——将有关状态存入各ConcreteObserver对象;
    ——当它的状态发生改变时,向它的各个观察者发出通知。

    ConcreteObserver(具体观察者)
    ——维护一个指向ConcreteSubject对象的引用;
    ——存储有关状态,这些状态应与目标的状态保持一致;
    ——实现Observer的更新接口以使自身状态与目标的状态保持一致。

    观察者模式按照以下方式进行协作:

      1、当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;

      2、在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。

    适用场合

    在以下任一情况下都可以使用观察者模式:

      1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;

      2、当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;

      3、当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。

    代码实现

    Observer.h

      1 /**
      2 * File name: Observer.h
      3 * Date: 2017.10.11
      4 * Description:  Define the observer
      5 */
      6 #pragma once
      7 #include <iostream>
      8 #include <set>
      9 #include <string>
     10 using namespace std;
     11 //抽象主题角色Subject
     12 class CObservable;
     13 //抽象观察者角色
     14 class CObserver
     15 {
     16 public:
     17     CObserver() {};
     18     virtual ~CObserver() {};
     19     //当被观察者的目标发生变化时,通知调用该方法
     20     //来自被观察者pObs,扩展参数为pArg
     21     virtual void Update(CObservable* pObs, void* pArg = NULL) = 0;
     22 };
     23 
     24 //被观察者,即Subject
     25 class CObservable
     26 {
     27 public:
     28     CObservable() : m_bChanged(false) {};
     29     virtual ~CObservable() {};
     30     void Attach(CObserver* pObs);            //注册观察者
     31     void Detach(CObserver* pObs);            //注销观察者
     32     void DetachAll();                        //注销所有观察者
     33     void Notify(void* pArg = NULL);            //若状态变化,则遍历观察者,逐个通知更新
     34     bool HasChanged();                        //测试目标状态是否变化
     35     int GetObserversCount();                //获取观察者数量
     36 protected:
     37     void SetChanged();                        //设置状态变化!!!必须继承CObservable才能设置目标状态
     38     void ClearChanged();                    //初始化目标为未变化状态
     39 private:
     40     bool m_bChanged;
     41     set<CObserver*> m_setObs;
     42 };
     43 
     44 void CObservable::Attach(CObserver* pObs)
     45 {
     46     if (!pObs)
     47         return;
     48     m_setObs.insert(pObs);
     49 }
     50 
     51 void CObservable::Detach(CObserver* pObs)
     52 {
     53     if (!pObs)
     54         return;
     55     m_setObs.erase(pObs);
     56 }
     57 
     58 void CObservable::DetachAll()
     59 {
     60     m_setObs.clear();
     61 }
     62 
     63 void CObservable::SetChanged()
     64 {
     65     m_bChanged = true;
     66 }
     67 
     68 void CObservable::ClearChanged()
     69 {
     70     m_bChanged = false;
     71 }
     72 
     73 bool CObservable::HasChanged()
     74 {
     75     return m_bChanged;
     76 }
     77 
     78 int CObservable::GetObserversCount()
     79 {
     80     return m_setObs.size();
     81 }
     82 
     83 void CObservable::Notify(void* pArg)
     84 {
     85     if (!HasChanged())
     86         return;
     87     cout << "notify observers..." << endl;
     88     ClearChanged();
     89     set<CObserver*>::iterator itr = m_setObs.begin();
     90     for (; itr != m_setObs.end(); itr++)
     91     {
     92         (*itr)->Update(this, pArg);
     93     }
     94 }
     95 
     96 //具体主题角色
     97 //bloger是发布者,即被观察者(subject)
     98 class CBloger : public CObservable
     99 {
    100 public:
    101     void Publish(const string &strContent)
    102     {
    103         cout << "bloger publish, content: " << strContent << endl;
    104         SetChanged();
    105         Notify(const_cast<char*>(strContent.c_str()));
    106     }
    107 };
    108 
    109 //portal是发布者,即被观察者(subject)
    110 class CPortal : public CObservable
    111 {
    112 public:
    113     void Publish(const string &strContent)
    114     {
    115         cout << "portal publish, content: " << strContent << endl;
    116         SetChanged();
    117         Notify(const_cast<char*>(strContent.c_str()));
    118     }
    119 };
    120 
    121 //RSS阅读者,观察者
    122 class CRssReader : public CObserver
    123 {
    124 public:
    125     CRssReader(const string &strName) : m_strName(strName) {}
    126     virtual void Update(CObservable* pObs, void* pArg = NULL)
    127     {
    128         char* pContent = static_cast<char*>(pArg);
    129         //观察多个目标
    130         if (dynamic_cast<CBloger*>(pObs))
    131         {
    132             cout << m_strName << " updated from bloger, content: " << pContent << endl;
    133         }
    134         else if (dynamic_cast<CPortal*>(pObs))
    135         {
    136             cout << m_strName << " updated from portal, content: " << pContent << endl;
    137         }
    138     }
    139 private:
    140     string m_strName;
    141 };
    142 
    143 //Mail阅读者,观察者
    144 class CMailReader : public CObserver
    145 {
    146 public:
    147     CMailReader(const string &strName) : m_strName(strName) {}
    148     virtual void Update(CObservable* pObs, void* pArg = NULL)
    149     {
    150         char* pContent = static_cast<char*>(pArg);
    151         if (dynamic_cast<CBloger*>(pObs))
    152         {
    153             cout << m_strName << " updated from bloger, content: " << pContent << endl;
    154         }
    155         else if (dynamic_cast<CPortal*>(pObs))
    156         {
    157             cout << m_strName << " updated from portal, content: " << pContent << endl;
    158         }
    159     }
    160 private:
    161     string m_strName;
    162 };

    main.cpp

     1 /**
     2 * File name: main.cpp
     3 * Date: 2017.10.11
     4 * Description:  An example of using observer
     5 */
     6 #include "Observer.h"
     7 int main()
     8 {
     9     //目标(被观察者)
    10     CBloger* pBloger = new CBloger();
    11     CPortal* pPortal = new CPortal();
    12 
    13     //观察者 一个观察者可以观察多个目标
    14     CRssReader* pRssReader = new CRssReader("rss reader");
    15     CMailReader* pMailReader = new CMailReader("mail reader");
    16     pBloger->Attach(pRssReader);        //bloger注册观察者
    17     pBloger->Attach(pMailReader);        //bloger注册观察者
    18     pPortal->Attach(pRssReader);        //portal注册观察者
    19     pPortal->Attach(pMailReader);        //portal注册观察者
    20     //博客发布消息
    21     pBloger->Publish("blog shares pattren of design");
    22     cout << endl;
    23 
    24     //门户发布消息
    25     pPortal->Publish("portal shares pattern of design");
    26     cout << "
    portal detached mail reader" << endl;
    27 
    28     pPortal->Detach(pMailReader);
    29 
    30     cout << "portal observers count:" << pPortal->GetObserversCount() << endl << endl;
    31     pPortal->Publish("portal shares pattern of design");
    32 
    33     system("pause");
    34     return 0;
    35 }

    vs2017运行结果

     

    转自:

    http://www.cnblogs.com/carsonzhu/p/5770253.html

  • 相关阅读:
    Python 快速入门笔记(4):表达式
    Python 快速入门笔记(3):常量和变量
    selenium中的下拉框处理模块Select
    HTML基础之JS中的字符转义--转义中文或特殊字符
    HTML基础之JS中的序列化和反序列化-----字符串的json类型与字典之间的相互转换
    【转载】Jenkins安装以及邮件配置
    HTML基础
    python之用unittest实现接口参数化示例
    python之使用单元测试框架unittest执行自动化测试
    python之造测试数据-faker(转载)
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/7645206.html
Copyright © 2011-2022 走看看