• 设计模式之实现观察者模式


    /**********************************************************

    CPaper.h

    **********************************************************/


    #pragma  once
    #include <iostream>
    #include <string>
    using namespace std;

    class CPaper{
    public:
     string context;
    public:
     CPaper(){}

     CPaper(const string& _cont){
      context = _cont;
     }

     CPaper(const CPaper& cInst){
      context = cInst.context;
     }

     CPaper& operator=(const CPaper& rhs){
      context = rhs.context;
      return *this;
     }

     void viewPaper(){
      cout<<context<<endl;
     }

     bool isEmpty(){
      return context == "";
     }
    };

    /***************************************************

    Observer.h

    ***************************************************/

    /*
    实现报社与报纸订阅者之间的: 主题与观察者模式
    这里只实现,一个主题有多个观察者,而一个观察者只有一个主题的情况。
    如果一个观察者有多个主题,情况也类似。
    by 何戬,  hejian@cad.zju.edu.cn
    */

    #pragma  once
    #include "CPaper.h"
    #include <iostream>
    #include <string>
    using namespace std;

    class PaperProvider;

    /////////////////////////
    //观察者的基类,针对接口编程
    class CObserver
    {
    public:
     virtual void Update(const CPaper& _inPaper) = 0;
    };

    ///////////////////////
    //再提供专门为报纸订阅者写的基类
    //之所以之CObserver继承,我是为是避免使用多重继承
    //因为在C++中实现多重继承的代码是比较大的,按照书里的做法,这个类也是一个接口。
    class CSubscriber : public CObserver
    {
    public:
     CPaper m_paper;
     string m_SubscriberName;

     //假设只能订阅一个主题
     PaperProvider* m_paperProvider;

    public:
     virtual void display() = 0;
     virtual void addProvider(PaperProvider *paper);
     virtual void removeProvider();

     string& getSubScriberName(){
      return m_SubscriberName;
     }


     CSubscriber(PaperProvider *paper, string name) : m_paperProvider(paper), m_SubscriberName(name){}
    };

    /////////////////////////////////
    //实观察者类(concrete observer)
    class SimpleEditionSubscriber : public CSubscriber
    {
    public:
     //这个就是针对接口编程的好处
     void Update(const CPaper& _inPaper){
      //假设这个简易版本的报名,只显示第一个字符
      m_paper.context = _inPaper.context[0];
      //这步是为了简单才直接调用了,其实应该是订阅者自己检查是否有新的报纸,自己才调用display的
      display();
     }

     void display(){
      cout<<"I'm a simple edition subscriber!"<<endl;
      m_paper.viewPaper();
     }

    public:
     SimpleEditionSubscriber(PaperProvider *paper, string name);
    };

    /////////////////////////////////
    //实观察者类(concrete observer)
    class FullEditionSubscriber : public CSubscriber
    {
    public:
     void Update(const CPaper& _inPaper){
      m_paper = _inPaper;
      //这步是为了简单才直接调用了,其实应该是订阅者自己检查是否有新的报纸,自己才调用display的
      display();
     }

     void display(){
      cout<<"I'm "<<m_SubscriberName<<" : a Full edition subscriber!"<<endl;
      cout<<">>>>>>Begin read"<<endl;
      m_paper.viewPaper();
      cout<<">>>>>>End read"<<endl;
     }

    public:
     FullEditionSubscriber(PaperProvider *paper, string name);
    };

    /********************************************************

    Subjects.h

    ********************************************************/

    #pragma once
    #include <iostream>
    #include <list>
    #include "CPaper.h"
    #include "Observer.h"
    using namespace std;

    /*
    只实现了单个报刊提供商,
    如果要实现多个报刊提供商,那我们只需要再做一个纯虚基类,这个基类继承CSubject的三个主题接口,
    其它所有的实主题类都派生自这个纯虚基类
    */


    ///////////////////////////////////////////////////////
    //这是一个主题类的基类接口
    //实现三个最基本的主题类操作
    //如果有多个主题,那么必须都从这个类继承接口。
    class CSubject
    {
    public:
     //注册一个新的观察者
     virtual void registerObject(CSubscriber* newSubscriber) = 0;

     //删除一个已有的观察者
     virtual void removeObject(CSubscriber* delSubscriber) = 0;

     //通知一个已有的观察者
     virtual void notifyObject() = 0;
    };

    //////////////////////////////////////////////////////
    //定义一个新的实观察者
    class PaperProvider : public CSubject
    {
    private:
     list<CSubscriber*> m_Subscriber;

     //假设只能做一份报纸
     CPaper m_paper;

    public:
     void registerObject(CSubscriber* newSubscriber){
      if(!newSubscriber)
       return;
      m_Subscriber.push_back(newSubscriber);
     }

     void removeObject(CSubscriber* delSubscriber){
      if(!delSubscriber)
       return;

      //通过name来删除观察者,其实应该通过id来删除,
      //为了简单起见所以我用了name,而且name不会重复
      string name = delSubscriber->getSubScriberName();

      list<CSubscriber*>::iterator ibeg;
      list<CSubscriber*>::iterator iend = m_Subscriber.end();
      for(ibeg = m_Subscriber.begin(); ibeg != iend; ++ibeg)
      {
       CSubscriber* cpos = *ibeg;
       if( name == cpos->getSubScriberName()){
        //delete cpos;
        //cpos = NULL;
        ibeg = m_Subscriber.erase(ibeg);
        return;
       }
      }
     }

     void notifyObject(){
      if( m_paper.isEmpty() )
       return;
      //通知每一个objserver
      list<CSubscriber*>::iterator ibeg;
      list<CSubscriber*>::iterator iend = m_Subscriber.end();
      for(ibeg = m_Subscriber.begin(); ibeg != iend; ++ibeg)
      {
       CSubscriber* cpos = *ibeg;
       cpos->Update(m_paper);
      }
     }

     void PrintPaper(const string& str){
      //新报纸出印刷完毕
      m_paper = CPaper(str);
      //发送给每个观察者(订阅者)
      notifyObject();
     }

    public:
     //这里和书上不一样, Java自己提供了垃圾回收机制,但是C++中我们必须手动来清理这些对象
     ~PaperProvider(){
      /* 想了一下,还是留给用户去删除吧。因为也许用户还定了其它报纸呢?
      list<CSubscriber*>::iterator ibeg;
      list<CSubscriber*>::iterator iend = m_Subscriber.end();
      for(ibeg = m_Subscriber.begin(); ibeg != iend; ++ibeg)
      {
       CSubscriber* cpos = *ibeg;
       delete cpos;
       cpos = NULL;
      }
      */
      m_Subscriber.empty();
     }

    };

    /***************************************************************

    Observer.cpp

    ***************************************************************/

    /*
    没办法,这个模式要相互包含头文件,所以只能使用前置定义了
    by 何戬, hejian@cad.zju.edu.cn
    */

    #include <iostream>
    using namespace std;

    #include "Subjects.h"
    #include "Observer.h"

    ///////////////////////////////////////////////////////////////////////////////
    /////////////////////////CSubscriber Implementation////////////////////////////

    //订阅新主题
    void CSubscriber::addProvider(PaperProvider *paper)
    {
     //先把退订原先的主题
     removeProvider();
     
     m_paperProvider = paper;

     if(m_paperProvider){
      m_paperProvider->registerObject(this);
     }
     
    }

    //退订主题
    void CSubscriber::removeProvider()
    {
     if( !m_paperProvider )
      return;

     m_paperProvider->removeObject(this);
    }


    ///////////////////////////////////////////////////////////////////////////////
    /////////////////////////FullEditionSubscriber Implementation////////////////////////////
    SimpleEditionSubscriber::SimpleEditionSubscriber(PaperProvider *paper, string name):
    CSubscriber(paper, name)
    {
     if(!m_paperProvider)
      return;

     m_paperProvider->registerObject(this);
    }

    ///////////////////////////////////////////////////////////////////////////////
    /////////////////////////SimpleEditionSubscriber Implementation////////////////////////////
    FullEditionSubscriber::FullEditionSubscriber(PaperProvider *paper, string name):
    CSubscriber(paper, name)
    {
     if(!m_paperProvider)
      return;

     m_paperProvider->registerObject(this);
    }

    /***************************************************************

    testObserver.cpp

    ***************************************************************/

    /*
     设计模式: 观察者模式
     by 何戬  hejian@cad.zju.edu.cn
     2009. 6. 1
    */
    #include <iostream>
    #include "Subjects.h"
    #include "Observer.h"

    using namespace std;


    int main()
    {

     //
     cout<<"::::::::::::The First Day:::::::::::::::"<<endl;
     //生成一个主题(报刊提供商)
     PaperProvider* paperPvd = new PaperProvider();

     //生成一个全副面订阅者来订阅这个主题
     FullEditionSubscriber *fullpaperSbc = new FullEditionSubscriber(paperPvd, "hejian");
     
     //主题出版一份报纸
     paperPvd->PrintPaper("hello the first free paper");

     //
     cout<<"::::::::::::The Second Day:::::::::::::::"<<endl;
     //再多一个订阅者
     FullEditionSubscriber *fullpaperSbc2 = new FullEditionSubscriber(paperPvd, "rabbit");

     //主题出版一份报纸
     paperPvd->PrintPaper("hello the first free paper: we have two full edtion subsribers");

     //
     cout<<"::::::::::::The Third Day:::::::::::::::"<<endl;
     //多一个简化版订阅者,free的哈哈,因为只能看一份报纸的每一个字母。
     SimpleEditionSubscriber* sp1 = new SimpleEditionSubscriber(paperPvd, "simple pig");

     //主题出版一份报纸
     paperPvd->PrintPaper("a simple pig come into!");


     //
     cout<<"::::::::::::The fourth Day:::::::::::::::"<<endl;
     fullpaperSbc2->removeProvider();

     //主题出版一份报纸
     paperPvd->PrintPaper("a full edition subscriber is removed!");

     delete sp1;
     delete fullpaperSbc2;
     delete fullpaperSbc;
     delete paperPvd;
    }

  • 相关阅读:
    Spring mvc配置
    css选择器
    网页全屏背景设计
    2018年的第一篇
    总结2016,规划2017
    Jenkins上Git ssh登陆配置
    Jenkins构建项目,JAVA_HOME is not defined correctly
    运行Jmeter.bat出错:Not able to find java executor or version. Please check your installation. errorlevel=2
    Selenium获取input值的两种方法:WebElement.getAttribute("value")和WebElement.getText()
    Jmeter
  • 原文地址:https://www.cnblogs.com/skyofbitbit/p/2756446.html
Copyright © 2020-2023  润新知