Я довольно широко использовал шаблон команд, и он хорошо работает. Однако обычно не обсуждается где экземпляры команд созданы.
Следующие примеры иллюстрируют эту проблему: 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()
установлен в правда. Следовательно, Document::setText()
установит m_text
,
Очевидно, что все функции установки документа должны следовать if (commandManager()->isActive()) { ... } else { ... }
парадигма. Это потому, что сами Команды создаются в функциях сеттера.
Вопрос сейчас: Это хороший способ реализовать шаблон команды? Или есть более чистые решения для создания команд, в то же время имея хороший API?
Пожалуйста, будьте многословны со своими ответами.
Я думаю, что было бы довольно уродливо, чтобы повторить if (commandManager()->isActive())
везде … наверное, приятнее иметь setText
всегда делай SetTextCommand
путь, и создайте новый setTextImmediate
метод, который SetTextCommand
можешь использовать.