我正在尝试添加一个访问者到现有的图书馆。访问者必须能够访问来自不同项目的一些类。
假设我的解决方案有以下项目:ProjectA
,ProjectB
,它们分别包含一个类:NodeA
,NodeB
。由于访问者只是类成员在类之外的实现,我认为它的依赖关系将不允许它被放置在另一个项目中。因此,如果我想创建一个访问者,可以访问NodeA
和NodeB
对象,我不能使用一个简单的访问者。
这个评估正确吗?
我正在考虑一些解决方案来克服这个问题。
- 将其中一个类移动到另一个项目并在那里实现visitor(这不是一个可行的解决方案)。
- 添加一个额外的间接。为每个项目的访问者实现创建一个类。并创建一个"首席访问者"。
我错过了什么吗?有更好的方法吗?
下面是我的访问者实现。请注意,为了简单起见,我删除了标题保护符。
/// --- Node.h in project A ---
class Visitor;
class Node {
public:
Node() = default;
virtual ~Node() = default;
virtual void accept(Visitor & v) = 0;
};
/// --- NodeA.h in project A ---
#include "Visitor.h"
class NodeA : public Node {
public:
void accept(Visitor & v);
};
/// --- NodeB.h in project B ---
#include "Visitor.h"
class NodeB : public Node {
public:
void accept(Visitor & v);
};
/// --- Visitor.h ---
#include "Node.h"
class NodeA;
class NodeB;
class Visitor {
public:
Visitor() = default;
virtual ~Visitor() = default;
virtual void visit(const Node & node);
virtual void visit(const NodeA & node);
virtual void visit(const NodeB & node);
};
// --- Visitor.cpp ---
#include "Visitor.h"
#include "NodeA.h"
void Visitor::visit(const Node & node)
{
// implementation
}
void Visitor::visit(const NodeA & node)
{
// implementation
}
void Visitor::visit(const NodeB & node)
{
// implementation
}
如果NodeA
和NodeB
之间除了能够接受访问者并将其存储在a(例如std::vector<std::unique_ptr<Node>>
)中之外没有任何共同之处,请考虑使用std::variant
。
代码看起来像这样:
#include <variant>
#include <iostream>
#include <vector>
class NodeA {};
class NodeB {};
using Node = std::variant<NodeA, NodeB>;
class Visitor
{
public:
void operator()(NodeA & node)
{
std::cout << "encountered A" << std::endl;
}
void operator()(NodeB & node)
{
std::cout << "encountered B" << std::endl;
}
};
int main()
{
std::vector<Node> nodes;
nodes.emplace_back(NodeA{});
nodes.emplace_back(NodeA{});
nodes.emplace_back(NodeB{});
nodes.emplace_back(NodeA{});
nodes.emplace_back(NodeB{});
nodes.emplace_back(NodeB{});
Visitor visitor;
for (auto & node : nodes)
{
std::visit(visitor, node);
}
}
这样NodeA
,NodeB
和访问者的实现基本上是解耦的。
如果我将访问者接口类放在与Node相同的项目中,并且只在派生节点头中使用它,我可以将派生访问者类放在不同的项目中,这将取决于所有内容(基节点和派生节点以及基访问者)。visit方法将被动态地分配给适当的visitor实例。