c++ - 监听器类继承者 - 对监听类的 const 或非常量引用?

标签 c++ object design-patterns listener encapsulation

代码库的一个非常常见的模式是 Listener 事件,如下所示:

 class Frobulator
 {
 public:
      class Listener
      {
      private:
          // only frobulators can frob
          friend class Frobulator;
          virtual void onFrobbed() = 0;
      }

      void maybeFrob()
      {
          // assume we always frob, but maybe we only do it sometimes
          // and the caller won't know if a call will do it
          for (auto& l: listeners)
          {
               l->onFrobbed();
          }
      }

      void addListener(Listener* l)
      {
           listeners.push_back(l);
      }

 private:
     std::vector<Listener*> listeners;
 }

然后,一个类继承了Listener,可以向Frobulator注册为监听器。当 Frobulator 在某个调用者(不一定是听众)的调用后颤抖时,听众将被告知。

我真正的问题是,监听器是否应该“内部”监听,因此需要对 Frobulator 的非常量引用,但使用 private 进行管理Listener性质?

 class FrobReactor: private Frobulator::Listener
 {
 public:
      FrobReactor(Frobulator& frobulator_)
           frobulator(frobulator)
      {
           frobulator.addListener(this);
      }

 private:
      void onFrobbed() override
      {
           // react!
      }

      Frobulator& frobulator;
 }

 // and externally ...
 Frobulator theFrobber;
 FrobReactor reactor(theFrobber);
 theFrobber.maybeFrob();

或者监听器应该采用常量引用(如果不需要,甚至不引用),确认 FrobReactor 不会修改 Frobulator ,但宣传它是一个 Frobulator::Listener 并期望客户端代码将其连接起来:

class FrobReactor: public Frobulator::Listener
{
public:
    FrobReactor(const Frobulator& frobulator_):
        frobulator(frobulator_)
    {
    }

private:
    void onFrobbed() override
    {
        // react!
    }

    const Frobulator& frobulator;
}

 // and externally
 Frobulator theFrobber;
 FrobReactor reactor(theFrobber);
 theFrobber.addListener(&reactor);
 theFrobber.maybeFrob();

或者,addListener 方法可以设为 const,而监听器列表 mutable,然后第一个方法也可以使用非常量引用,但这感觉像是 hack .

是否有“正确”的方法来做到这一点?

最佳答案

我不会在 FrobReactor 中存储对观察到的(或听到的)Frobulator 的引用。相反,我会将对 Frobulator 实例的常量引用传递给 onFrobbed 方法。

class Listener
{
private:
    // only frobulators can frob
    friend class Frobulator;
    virtual void onFrobbed(const Frobulator& frobulator) = 0;
}

并且,改编maybeFrob:

void maybeFrob()
{
    // assume we always frob, but maybe we only do it sometimes
    // and the caller won't know if a call will do it
    for (auto& l: listeners)
    {
        l->onFrobbed(*this);
    }
}

至于 addListener 是否应该是 const(因此,监听器的 vector 是否应该是可变的),这取决于您要实现的目标。我同意这感觉很老套,但另一方面,如果你想确保你的 API 的客户端只处理 const Frobulators,那么这是一种方法。另一种方法是在您的 API 中的某处使用一种方法来处理向 Frobulators 添加监听器,如下所示:

void addListener(const Frobulator& frobulator, Frobulator::Listener& listener) {
    Frobulator& nonConst = // obtain non-const reference to this frobulator
    nonConst.addListener(listener);
}

这实际上取决于您的设计。否则,如果您只想保护监听器免于修改 Frobulator,那么将 const 引用传递给 'onFrobbed 方法似乎就足够了。

最后,我会像这样更改 addListener:

void addListener(Listener& listener)
{
    listeners.push_back(&listener);
}

这是一个很小的变化,但我更喜欢在转移所有权时只传递一个指针,除非有其他原因需要传递一个指针。当然,在任何一种情况下,您都必须确保您的监听器不会被删除(超出范围)。

关于c++ - 监听器类继承者 - 对监听类的 const 或非常量引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35478640/

相关文章:

java - 如何通知正在运行的线程发生更改

c++ - 当编译时已知引用占用结构中的空间时,是否错过了优化?

C++复制结构的内容

python - 随机列表中的对象属性在 Python 中不可访问

java - 根据类大小创建对象的内存分配量

java - 基于对象状态的 getter /属性可用性(例如,基于解析状态)

c++ - 代码块不正确的 c++ 输出

c++ - 跨翻译单元访问 const 变量

java - 扩展或重写外部基类以添加随后也存在于外部子类中的功能

c# - 具有 2 个状态的 ListView 控件的设计模式?