【问题标题】:Observer design pattern in C++C++中的观察者设计模式
【发布时间】:2010-02-08 21:53:59
【问题描述】:

STL 中是否已经定义了观察者设计模式(如 Java 中的 java.util.Observer 和 java.util.Observable)?

【问题讨论】:

  • 可能是另一种语言标准库的示例,其中内置了观察者模式。
  • 你可以接受提升吗?如果不是,我愿意发布一个标准的非增强实现。

标签: c++ design-patterns observer-pattern


【解决方案1】:

没有,但Boost.Signals2 给了你类似的东西。

【讨论】:

  • +1,Boost.Signals 很棒。如果你有多个线程,还要检查 Signals2。
  • Boost.Signals 已弃用,应使用 Boost.Signals2。
【解决方案2】:

据我所知,STL 没有观察者模式的实现。不过,TR2 中有一个标准库的 Signal/Slot 提案。

有很多库为观察者模式提供实现 Qt 库是先驱之一。 boost 库有一个实现(参见 Boost::Signals 和 Boost::Signals2)。

Poco C++ 库有一个简洁的观察者模式实现(参见 NotificationCenter)。

libsigc++、cpp-events 是其他一些提供信号/插槽实现的库。

【讨论】:

    【解决方案3】:

    不,它没有。 C++ STL 比 Java 的标准库小得多。如果您正在寻找一些东西来扩展几乎所有东西都支持的 STL,那么看看 Boost 库是值得的。在这种情况下,您可能需要查看提供信号/插槽模型的 Boost.Signals

    【讨论】:

      【解决方案4】:

      这是一个参考实现(来自Wikipedia)。

      #include <iostream>
      #include <string>
      #include <map>
      #include <boost/foreach.hpp>
      
      class SupervisedString;
      class IObserver{
      public:
          virtual void handleEvent(const SupervisedString&) = 0;
      };
      
      
      class SupervisedString{ // Observable class
          std::string _str;
          std::map<IObserver* const, IObserver* const> _observers;
      
          typedef std::map<IObserver* const, IObserver* const>::value_type item;
      
          void _Notify(){
              BOOST_FOREACH(item iter, _observers){
                  iter.second->handleEvent(*this);
              }
          }
      
      public:
          void add(IObserver& ref){
              _observers.insert(item(&ref, &ref));
          }
      
          void remove(IObserver& ref){
              _observers.erase(&ref);
          }
      
          const std::string& get() const{
              return _str;
          }
      
          void reset(std::string str){
              _str = str;
              _Notify();
          }
      };
      
      
      class Reflector: public IObserver{ // Prints the observed string into std::cout
      public:
          virtual void handleEvent(const SupervisedString& ref){
              std::cout<<ref.get()<<std::endl;
          }
      };
      
      class Counter: public IObserver{  // Prints the length of observed string into std::cout
          virtual void handleEvent(const SupervisedString& ref){
              std::cout<<"length = "<<ref.get().length()<<std::endl;
          }
      };
      
      int main(){
      
          SupervisedString str;
          Reflector refl;
          Counter    cnt;
      
          str.add(refl);
          str.reset("Hello, World!");
          std::cout<<std::endl;
      
          str.remove(refl);
          str.add   (cnt);
          str.reset("World, Hello!");
          std::cout<<std::endl;
      
          return 0;
      }
      

      【讨论】:

      • 很难认真对待使用非法成员函数名称(例如 _Notify)的 C++ 实现。
      • 显然它还有其他问题。查看讨论页面:en.wikipedia.org/wiki/…
      • hmmm...也许我的答案应该是“将位于此处的代码修改为参考实现”:(
      • C++ 实现已从维基百科文章中删除。
      • @NickBedford 是有效的 C++,因为它可以编译吗?该标准实际上非常明确:来自 §2.10.3.1 “每个包含双下划线 __ 或以下划线后跟大写字母的标识符都保留给实现以供任何使用。”我认为应该更改示例,此外我认为该函数没有真正有用的理由以下划线为前缀。添加 §17.6.4.3.2 “如果程序在保留名称的上下文中声明或定义名称,除非本条款明确允许,否则其行为未定义。”
      【解决方案5】:
      #include <iostream>
      #include <string>
      #include <set>
      using namespace std;
      class Subject;
      class Observer {
      public:
        virtual void update(Subject & subject) = 0;
      };
      // also knows as Observable in literature
      class Subject
      {
        string state;
        set<Observer*> observers;
      public:
        void attachObserver(Observer *o) { observers.insert(o); }
        void detachObserver(Observer *o) { observers.erase(o); }
        void notifyObservers()
        {
          for (auto &o : observers)
          {
            o->update(*this);
          }
        }
        string getState() { return state; }
        void changeState(const string & s)
        {
          state = s;
          notifyObservers();
        }
      };
      class ObserverImpl : public Observer
      {
        string state;
      public:
        void update(Subject & sbj) override
        {
          state = sbj.getState();
        }
        string getState() { return state; }
      };
      int main()
      {
        ObserverImpl a, b, c;
        Subject subject;
        subject.attachObserver(&a);
        subject.attachObserver(&b);
        subject.attachObserver(&c);
        subject.changeState("Observer pattern");
        cout << a.getState() << endl;
        cout << b.getState() << endl;
        cout << c.getState() << endl;
        return 0;
      }
      

      另请参阅 UML/流程图http://codepatterns.ddns.net/

      【讨论】:

      • 链接已损坏。
      【解决方案6】:

      Observer design pattern 未在 STL 中定义。你可以参考"Gang of four" Design Patterns book 或者谷歌搜索应该提供足够的细节来实现它。如果这个问题没有很快得到回答,我会发布一个简单的例子。

      【讨论】:

      • 或者您可以复制粘贴某人在另一个答案中链接的维基百科实现
      • 谢谢!升压信号看起来很有趣。我使用 Boost 来生成随机数,但从来没有像他们所说的那样用于观察者模式或信号。无论如何,我认为评估 GOF 观察者模式和 Boost Signals 至少出于学术目的是一个好主意。
      【解决方案7】:
                   #include<iostream>
                   #include<string.h>
                   #include<vector>
                   #include<algorithm>
                   using namespace std;
      
      
                   class Customer;
                   class flipkart
                   {
                      vector<Customer*>list;
                      vector<Customer*>::iterator it;
                      public:
                      void Register(Customer *customer)
                      {
                         list.push_back(customer);
                      }
                      void unregister(Customer *customer)
                      {
                          list.erase(remove(list.begin(), list.end(),customer), list.end()); 
                      }
      
                      void notify(string item,float vprice);
                   };
      
      
                   class observer
                   {
                       public:
                       virtual void update(string item,float vprice)=0;
                   };
                   class Customer:public observer
                   {
                       string name;
                       public:
                       Customer(string n)
                       {
                           name=n;
                       }
      
                       void update(string item,float vprice)
                       {
                           cout<<"**Flipkart**updated price for "<<item<<" is:"<<vprice<<" Rupees only, request recieved by "<<name<<endl;
                       }
                   };
      
                   void flipkart::notify(string item,float vprice)
                   {
                       for(it=list.begin();it!=list.end();it++)
                       {
                           (*it)->update(item,vprice);
                       }
                   }
      
                   class product:public flipkart
                   {
                       public:
                       void change_price(string item,float vprice)
                       {
                           notify(item,vprice);
                       }
                   };
      
                   int main()
                   {
                       Customer customer1("Dhoni"),customer2("Yuvraj"),customer3("Kohli");
                       product LCD;
      
                       LCD.Register(&customer1);
                       LCD.Register(&customer2);
                       LCD.Register(&customer3);
      
                       LCD.change_price("LCD HD2 TV",12000);
      
                       LCD.unregister(&customer2);
                       cout<<"after unregisterng customer2:\n";
      
                       LCD.change_price("LCD HD2 TV",11500);
                   }
      

      【讨论】:

      • 以上代码仅供想了解观察者设计模式基本用法的人参考,如有错误请指正谢谢....@THRINATH@。
      • 欢迎来到 StackOverflow!你能详细说明一下吗?这如何回答这个问题?
      猜你喜欢
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 2011-11-25
      • 2021-11-22
      • 2010-12-31
      • 2011-03-22
      • 2020-12-28
      相关资源
      最近更新 更多