监听器类继承器 - 对const类的const或非const引用进行监听?

时间:2016-02-18 10:18:26

标签: c++ object design-patterns listener encapsulation

代码库的一个非常常见的模式是这样的 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来说,听众会被告知。

我真正的问题是,如果听众在内部听#34;因此需要对private进行非const引用,而是使用Listener进行管理{ {1}}性质?

 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();

或者听众应该采用const-reference(如果你不需要也不参考),承认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设置为第一个方法也可以使用非const引用,但这感觉就像是一个黑客。

是否有&#34;权利&#34;这样做的方法?

1 个答案:

答案 0 :(得分:1)

我不会在FrobReactor中存储对观察到的(或听过的)Frobulator的引用。相反,我会将对Frobulator实例的const引用传递给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(因此,监听器的向量是否应该是可变的),这取决于你想要实现的目标。我同意它感觉很乱,但另一方面,如果你想确保你的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);
}

这取决于你的设计。否则,如果您只想保护侦听器不要修改Frobulators,那么将const引用传递给&#39; onFrobbed方法似乎就足够了。

最后,我会像这样更改addListener

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

这是一个很小的改动,但我更倾向于在转移所有权时传递指针,除非有其他理由传递指针。当然,你必须确保你的听众在任何一种情况下都不会被删除(超出范围)。