与受控制的RTTI使用相比,访客模式是否是更好的选择?

问题描述 投票:1回答:1

我经常发现自己试图使用boost / QT信号解耦物体。天真的方法是针对我要交流的每种具体类型,创建一个新的信号和插槽签名,并连接所有相关对象。这导致了访问者模式,理想情况下,我想发出一个访问者,并让所有听课都接待该访问者并执行操作。接口看起来像这样:

class IVisitor
{
public:
     Visit(IListener* Listener);
     Visit(ConcreteListener1* Listener);
     Visit(ConcreteListener2* Listener);
     //And so on from here 
};

同样,如果我想要多个命令,则需要使多个访问者:

class IListener
{
public:
     Visit(IVisitor* Listener);
     Visit(ConcreteVisitor1* Listener);
     Visit(ConcreteVisitor2* Listener);
     //And so on from here
};

对我来说,这似乎违反了开放/封闭原则,因为每次我想连接新的侦听器或实现新的访问者时,我总是不得不返回接口的更新。理想情况下,这将使用双重分派,并且如果不存在专用接口,则仅根据派生类根据使用基类接口接受的访问者来更改派生类,才能使基类保持完整。我知道这在C ++中是不可能的,因为函数重载和参数类型基于编译时信息。

通常,这就是在不支持它的程序中重新实现多个分派。

我已经看到许多关于访客模式的争论,似乎人们在使用和讨厌这种模式。看来其访客模式还是dynamic_cast?我已经实现了模板化的帮助程序类,该类可以在使用dynamic_cast进行更好的维护时自动执行可怕的if-else逻辑。所以我的问题是...当逻辑的维护在很大程度上自动化时,使用dynamic_cast的陷阱是否比访问者模式所提到的陷阱更糟?

编辑:

std :: visit确实确实是解决此多次分发问题的好方法。我能够使用以下一种衬里创建一个简单的消息传递系统:

std::visit(overloaded{ [&](auto arg) {Listener->Recieve(arg); } }, pCommand->AsVariant());
c++ c++17 dynamic-cast visitor-pattern multiple-dispatch
1个回答
1
投票

具有访客模式,

当将新的侦听器添加到IVisitor时,您可以保证现有访问者必须处理该新的侦听器。

使用简单的dynamic_cast,未处理的侦听器更有可能。根据(每个(因此没有统一的行为))类如何实现它,您可能会抛出不受支持的侦听器,或者回退到“默认实现”(不执行任何操作)。

dynamic_cast的替代方法是std::variant用法,对于访问者,它需要了解所有侦听器类型。

[std::variant有一个std::visit,它甚至可以进行多次分派:-)

所以,类似:

using ListenerVariant = std::variant<ConcreteListener1*, ConcreteListener2* /*..*/>;

class IListener
{
public:
    virtual ListenerVariant AsVariant() = 0;
// ...
};

然后

std::visit(overloaded{[](ConcreteListener1* l){/*..*/},
                      [](ConcreteListener2* l){/*..*/}},
           listener.AsVariant());

您可以保证所有案件都得到处理,(甚至可以退回)。

© www.soinside.com 2019 - 2024. All rights reserved.