命令模式:在哪里创建命令项?
Command Pattern: Where to create the Command items?
我已经相当广泛地使用了命令模式,而且效果很好。但是,通常不讨论的是在哪里 创建命令的实例。
以下示例说明了此问题:A 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);
}
}
SetTextCommand
由 CommandManager
处理如下:
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
.
显然,所有文档 setter 函数都必须遵循 if (commandManager()->isActive()) { ... } else { ... }
范例。这是因为命令本身是在 setter 函数中创建的。
现在的问题是:这是实现命令模式的好方法吗?或者是否有更简洁的解决方案来创建命令,同时具有良好的 API?
请详细回答你的问题。
我认为必须在任何地方复制 if (commandManager()->isActive())
会很丑陋...让 setText
始终执行 SetTextCommand
路径并创建一个新路径可能更好setTextImmediate
SetTextCommand
可以使用的方法。
我已经相当广泛地使用了命令模式,而且效果很好。但是,通常不讨论的是在哪里 创建命令的实例。
以下示例说明了此问题:A 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);
}
}
SetTextCommand
由 CommandManager
处理如下:
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
.
显然,所有文档 setter 函数都必须遵循 if (commandManager()->isActive()) { ... } else { ... }
范例。这是因为命令本身是在 setter 函数中创建的。
现在的问题是:这是实现命令模式的好方法吗?或者是否有更简洁的解决方案来创建命令,同时具有良好的 API?
请详细回答你的问题。
我认为必须在任何地方复制 if (commandManager()->isActive())
会很丑陋...让 setText
始终执行 SetTextCommand
路径并创建一个新路径可能更好setTextImmediate
SetTextCommand
可以使用的方法。