防止与复合访问者重复

Prevent duplication with a composite visitor

本文关键字:访问者 复合      更新时间:2023-10-16

我目前有两个访问者,他们都能正常工作。

#include <iostream>
#include <vector>
struct VisitorA
{
  void DoSomething(){}
};
struct VisitorB
{
  void DoSomething(){}
};
template <typename TVisitor>
static void RunAlgorithm(TVisitor& visitor);
int main()
{
  VisitorA visitorA;
  VisitorB visitorB;
  RunAlgorithm(visitorA);
  RunAlgorithm(visitorB);
}
template <typename TVisitor>
void RunAlgorithm(TVisitor& visitor)
{
  visitor.DoSomething();
}

现在我想在算法中应用两个访问者。我见过一个"复合"访问者,它存储多个访问者,并简单地将呼叫转发给每个访问者。要做到这一点,我似乎必须创建一个"ParentVisitor"类并从中派生,这样我就可以将ParentVisitor*存储在一个容器中:

#include <iostream>
#include <vector>
struct VisitorParent
{
  void DoSomething(){}
};
struct VisitorA : public VisitorParent
{
  void DoSomething(){}
};
struct VisitorB : public VisitorParent
{
  void DoSomething(){}
};
struct VisitorComposite : public VisitorParent
{
  void DoSomething()
  {
    for(unsigned int i = 0; i < Visitors.size(); ++i)
      {
      Visitors[i]->DoSomething();
      }
  }
  std::vector<VisitorParent*> Visitors;
};
static void RunAlgorithm(VisitorParent& visitor);
int main()
{
//   VisitorA visitor;
//   RunAlgorithm(visitor);
  VisitorA visitorA;
  VisitorB visitorB;
  VisitorComposite visitorComposite;
  visitorComposite.Visitors.push_back(&visitorA);
  visitorComposite.Visitors.push_back(&visitorB);
  RunAlgorithm(visitorComposite);
}
void RunAlgorithm(VisitorParent& visitor)
{
  visitor.DoSomething();
}

这样做的问题是,如果访问者有一些重复的功能,它将被执行两次。我曾想过将重复的代码移到VisitorParent,但后来我不知道如何对重复的部分说"只为其中一个访问者运行父代码,而不为其他访问者运行任何东西"。这似乎是"手动"的——有没有更好的机制来申请两个(或更多)访客?

在我看来,除了抽象的基本访问者类,您实际上总共需要四个具体访问者:

  1. 一个包含A和B中的常见运算
  2. 一个包含A特有的操作
  3. 一个包含B唯一的操作
  4. 一个合成器,可以通过抽象基类调用多个其他访问者

然后,通过与uniqueA组合common来处理原始访问者A的角色,通过与uniqueB组合common处理访问者B的角色,并且通过组合common、uniqueA和uniqueB来处理组合操作。

重复数据消除可以在合成器的出厂函数中完成,但您可能不想在合成器类中"烘焙"重复数据消除,以保留更多的灵活性。

使用访问者模式,如果运行它,您不会真的期望任何东西"中断"。因此,当您运行两次某个东西时,它可能会起作用是否运行两次是比访问者更高级别的问题,因此它不应该影响访问者的设计。

所以在这种情况下,手动可能是好的。

复合体的角色可能应该是一个控制器。它可能知道,如果一个访问者成功了,那么另一个访问者也不适合运行。为访问者添加一个返回值将为组合提供控制运行内容所需的反馈。控制器关心的是运行什么,访问者保持沉默。