命令模式:在哪里创建命令项

Command Pattern: Where to create the Command items?

本文关键字:命令 创建 模式 在哪里      更新时间:2023-10-16

我已经广泛地使用了命令模式,它工作得很好。然而,通常不讨论的是,其中是创建命令实例的地方。

下面的例子说明了这个问题:Document有一个函数setText(),它设置文本:

class Document {
public:
    void setText(const std::string text) {
        if (commandManager()->isActive()) {
            // called by SetTextCommand
            m_text = text;
        } else {
            // called somewhere in the application
            commandManager()->addAndExecute(new SetTextCommand(this, text));
        }
    }
    std::string text() const { return m_text; }
    CommandManager * commandManager() const { return m_commandManager; }
private:
    std::string m_text;
    CommandManager * m_commandManager;
}

这里,SetTextCommand将像这样执行document->setText(text):

class SetTextCommand : public Command {
public:
    SetTextCommand(Document * doc, const std::string & text)
        : Command(), m_doc(doc), m_oldText(doc->text()), m_text(text)
    {}
    void redo() override {
        m_doc->setText(m_text);
    }
    void undo() override {
        m_doc->setText(m_oldText, false);
    }
}

SetTextCommandCommandManager处理如下:

CommandManager::addAndExecute(Command * command) {
    m_doc->commandManager()->setActive(true); // THIS IS THE TRICK
    command->redo();
    m_doc->commandManager()->setActive(false);  // THIS IS THE TRICK
    m_stack->push_back(command);
}
这里的技巧是,当运行redo()时,CommandManager::isActive()被设置为true。因此,Document::setText()将设置m_text

显然,所有的Document setter函数都必须遵循if (commandManager()->isActive()) { ... } else { ... }范式。这是因为命令本身是在setter函数中创建的。

现在的问题是:这是实现命令模式的好方法吗?或者是否有更简洁的解决方案来创建命令,同时拥有一个漂亮的API?

请详细回答。

我认为到处复制if (commandManager()->isActive())是非常丑陋的…也许让setText总是做SetTextCommand路径更好,并创建一个SetTextCommand可以使用的新的setTextImmediate方法。