在设计个人项目的架构时,我提出了使用这两种模式的组合来解决架构问题的想法。在 MVC 上下文中,我需要实现由 UI 触发的各种类型的操作。我想从执行逻辑中抽象出控制器,并由模型负责。问题是我有不同类型的命令,并且根据命令的类型,它应该通过程序的不同逻辑路径进行路由。因此,我不仅需要将要执行的操作委托给命令本身,还需要对其进行路由。
这是我想要实现的设计示例:
class ICommand {
public:
virtual ~ICommand() {}
virtual void execute() = 0;
virtual void accept(CommandVisitor& visitor) = 0;
};
class CommandVisitor {
public:
void visit(SaveFileCommand& command);
void visit(SaveConfiguration& command);
void visit(SaveFileCommand& command) {
// logic
}
void visit(SaveConfiguration& command) {
// logic
}
};
class SaveFileCommand : public ICommand {
public:
void execute() override {
// logic
}
void accept(CommandVisitor& visitor) override {
visitor.visit(*this);
}
};
class SaveConfiguration : public ICommand {
public:
void execute() override {
// logic
}
void accept(CommandVisitor& visitor) override {
visitor.visit(*this);
}
};
我担心的是创建一个过于复杂的设计,我不确定这是否是解决我的问题的最佳方法。除此之外我还有什么选择?
划出一些示例命令来指导您的架构方向是个好主意。纯粹基于“SaveFileCommand”和“SaveConfigurationCommand”,我发现自己想知道您是否希望所有命令都像这些一样不变,或者其他命令是否会包含会改变您的内部状态的内容?这是一个关键的决策点,因为确定一组更具代表性的命令将极大地帮助您了解架构。例如:
我的强烈建议是继续写出您期望使用的命令,并在执行此操作时写出 CommandVisitor。为此,请利用单元测试来查看编写新命令或扩展 CommandVisitor 的体验,以及您是否发现可能需要将 CommandVisitor 分解为众多“命令处理程序”的摩擦。
如果您有兴趣阅读该领域的更多内容,您可以查看 Qt 的 QUndoCommand 架构,以获取在 GUI 中管理命令的灵感,或者查看任意数量的消息总线系统(例如 Kafka 或 Aeron)来管理系统之间的命令流。
如果您正在寻找更多特定于 C++ 的结构来帮助定义命令,我喜欢 Jarod42 的建议,即考虑 std::variant,因为它可以是对命令处理程序支持的命令组进行建模的好方法,而无需要求他们共享一个对象层次结构。我自己在类似的情况下也发现了很好的效果。