diff --git a/15_command.cpp b/15_command.cpp new file mode 100644 index 0000000..4f411c0 --- /dev/null +++ b/15_command.cpp @@ -0,0 +1,106 @@ +#include +#include +#include + +using namespace std; + +// The interface for communication between back and front +class Command { +public: + virtual bool execute() = 0; + virtual void undo() = 0; +}; + +// Reciever, which is a backend +class Light { + int status; +public: + Light() : status(0) {} + bool on() { + if (status == 0) { + status = 1; + cout << "Light on" << endl; + return true; + } else { + cout << "Light is already on" << endl; + return false; + } + } + + bool off() { + if (status == 1) { + status = 0; + cout << "Light off" << endl; + return true; + } else { + cout << "Light is already off" << endl; + return false; + } + } + + int get_status() { + return status; + } +}; + + +class OffCommand : public Command { + shared_ptr l; +public: + OffCommand(shared_ptr l) : l(l) {} + bool execute() override { + return l->off(); + } + + void undo() override { + l->on(); + } +}; + +class OnCommand : public Command { + shared_ptr l; +public: + OnCommand(shared_ptr l) : l(l) {} + bool execute() override { + return l->on(); + } + + void undo() override { + l->off(); + } +}; + +// The Invoker: manages and executes all commands. +// Any class that wants to operate the light can do so by simply +// executing a command, without needing to know the internal details +// of how the light works. +class RemoteControl { + vector> cmds; +public: + RemoteControl() {} + void exec_command(shared_ptr cmd) { + if (cmd->execute()) { + cmds.push_back(cmd); + } + } + + void undo() { + if (cmds.size() != 0) { + cmds[cmds.size() - 1]->undo(); + cmds.pop_back(); + } + } +}; + + +int main() { + auto l = make_shared(); + auto c1 = make_shared(l); + auto c2 = make_shared(l); + + RemoteControl rc; + rc.exec_command(c1); + rc.exec_command(c1); + rc.exec_command(c2); + rc.undo(); +} diff --git a/notes.md b/notes.md index b6b66ef..b6b8799 100644 --- a/notes.md +++ b/notes.md @@ -97,3 +97,11 @@ 责任链模式解决了这个问题。一个 handler 要么处理这个请求,要么交给下一个 handler 处理,增加处理逻辑时,只需要新增一个 handler,并且正确设置相应的 next 即可。这样,每个 handler 只关心自己的职责,所有 handler 处理清晰。当我们能将所有的 handler 组成一个链式或者树式的结构时,这会非常有用。 但也正如前面提到的,这不自然支持“一个请求需多个处理者同时处理”的场景。此时可以通过责任链进一步推广成“责任网”,观察者模式,流程引擎式结构等,增强责任链模式的处理能力。 + +## 命令模式(Command) + +一个系统通常分为前端和后端两部分,前端负责接收用户输入,后端处理核心业务逻辑。那么,前后端之间如何高效、清晰地交互呢?如果每个后端模块都暴露自己的接口,系统一旦扩展,接口之间容易混乱、难以维护。 + +命令模式通过引入统一的“命令对象”,将请求的发送者(前端)与执行者(后端)解耦。前端只需构造命令并发送,不关心命令的执行细节;而后端根据命令对象来执行相应逻辑。 + +更重要的是,所有操作都被抽象为统一的命令接口,这使得命令可以统一记录、排队、撤销、重做。多个前端只需绑定相同的命令对象,即可复用相同的后端逻辑,增强了代码复用性与系统扩展性。