C++自己的观察者模式

C++ Own Observer Pattern

本文关键字:观察者模式 自己的 C++      更新时间:2023-10-16

我正在设计一个观察器模式,它应该以这种方式工作:观察器调用EventDispatcherAddEventListener方法,并传递一个字符串,该字符串是eventPointerToItselfPointerToItsMemberMethod的名称

之后CCD_ 4发生在CCD_;它会查看订阅列表,如果有,则分配给该事件调用observeraction方法。

我来到这个EventDispatcher.h小心包含一些伪代码。

有两个问题:

  1. 如何在struct Subscription中定义action的类型
  2. 我走的路对吗

PS:不,我不会使用boost任何其他库。

#pragma once
#include <vector>
#include <string>
using namespace std;
struct Subscription
{
        void*                   observer;
        string                  event;
        /*  u_u  */             action;
};
class EventDispatcher
{
    private:
        vector<Subscription>    subscriptions;
    protected:
        void                    DispatchEvent ( string event );
    public:
        void                    AddEventListener ( Observer* observer , string event , /*  u_u  */ action );
        void                    RemoveEventListener ( Observer* observer , string event , /*  u_u  */ action );
};

此标头在EventDispatcher.cpp 中实现如下

#include "EventDispatcher.h"
void    EventDispatcher::DispatchEvent ( string event )
{
    int key = 0;
    while ( key < this->subscriptions.size() )
    {
        Subscription subscription = this->subscriptions[key];
        if ( subscription.event == event )
        {
            subscription.observer->subscription.action;
        };
    };
};
void    EventDispatcher::AddEventListener ( Observer* observer , string event , /* */ action )
{
    Subscription subscription = { observer , event , action );
    this->subscriptions.push_back ( subscription );
};
void    EventDispatcher::RemoveEventListener ( Observer* observer , string event , /* */ action )
{
    int key = 0;
    while ( key < this->subscriptions.size() )
    {
        Subscription subscription = this->subscriptions[key];
        if ( subscription.observer == observer && subscription.event == event && subscription.action == action )
        {
            this->subscriptions.erase ( this->subscriptions.begin() + key );
        };
    };
};

您可以定义一个Action类或传递一个lambda函数(C++11)。在后一种情况下,行动可以定义为

function<void (EventDispatcher*)> action;

您可以按照以下注册观察员

Observer * me = this;
observable->AddEventListener (this, "EventName", [me] (EventDispatcher* dispatcher) {
   // code here; me is available
});

您可能应该使用智能弱指针将Observer存储在EventDispatcher中,这样您就不必关心取消注册了。

编辑:添加了以下示例(只有一个订阅是可能的,但应该说明这个想法——你必须小心,不要引用已经不存在的对象)

struct Observable {
   std::weak_ptr<function<void (const Observable&)>> action;
   void AddEventListener (std::weak_ptr<function<void (const Observable&)>> theAction) {
      action = theAction;
   }
   void EventRaised () {
      if (!action.expired ()) {
         auto theAction = action.lock ();
         (*theAction) (*this);
      }
   }
};
struct Observer {
...
   void CallOnEvent (const Observable & observable) {
      // do something
   }
   // field to store the action as long as it is needed
   std::shared_ptr<function<void (const Observable&)>> action;
   void ... {
      auto me = this;
      action = std::make_shared<function<void (const Observable&)>> (
         [me] (const Observable& observable) {
             me->CallOnEvent (observable);
         }
      );
      // we could have as well used std::bind
      observable.AddEventListener (action);
   }
};

也许您应该创建一个由"users"派生的类:

class Action {
   public:
      friend class EventDispatcher;
      virtual SomeResultType DoThis() = 0;
   private:
      /* Some common data */
};

只需将一些派生自类Action类型的变量传递给AddEventListener。当相应的事件被触发时,只需填写公共数据并调用DoThis()方法。

void EventDispatcher::DispatchEvent ( string event )
{
    int key = 0;
    while ( key < this->subscriptions.size() )
    {
        Subscription subscription = this->subscriptions[key];
        if ( subscription.event == event )
        {
            subscription->action();
        };
    };
};

对于AddEventListener:

void EventDispatcher::AddEventListener ( Observer* observer , string event , Action* action )
{
    Subscription subscription = { observer , event , action );
    this->subscriptions.push_back ( subscription );
};

Action派生类的示例:

class myAction: public Action {
   public:
      // Implement the DoThis() method
      void SomeResultType DoThis() {
          cout << "Hello World!";
          return SomeValue;
      }
};
// To use the action,
myAction* act = new myAction;
myEventDispatcher.AddEventListener(someObserver, "HelloWorld", act);

这是实现操作(和回调)最安全的方法之一。

在最简单的形式中,u_u可以是一个函数指针,例如

typedef void (*u_u)(void*); // or whatever arguments u like

然后只需提供一个函数,该函数在事件被触发时被调用。

void myaction(void* arg)
{
  ...
}
Subscription s;
...
s.action = myaction;