行为型模式--命令
1、意图
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2、结构
3、参与者
Command:声明执行操作的接口;
ConcreteCommand:将一个接收者对象绑定于一个动作;
Client:创建一个具体命令对象并设定它的接收者;
Invoker:要求该命令执行这个请求;
Receiver:知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
4、适用性
当有如下需求时,可使用命令模式:
1)抽象出待执行的动作以参数化某对象。如过程语言中的回调函数机制,将函数先行注册,待某个条件满足时再调用。命令模式是回调机制的一个面向对象的替代品;
2)在不同的时刻指定、排列和执行请求;
3)支持取消操作。Command的Excute操作在实施前会先存储状态,在取消操作时通过该状态来消除操作的影响。Command必须添加UnExcute操作,以取消上一次Excute的调用效果;
4)支持修改日志,这样当系统崩溃时,这些修改可以被重新执行一遍;
5)用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共接口使得可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统;
5、代码示例
class Command { public: virtual ~Command(): virtual void Execute()= 0; protected: Command (); };
// OpenCommand打开一个名字由用户指定的文档。注意OpenCommand的构造器需要一个 // Application对象作为参数。AskUser是一个提示用户输入要打开的文档名的实现例程。 class OpenCommand : public Command { public: OpenCommand(Application); virtual void Execute(); protected: virtual const char* AskUser(); private: Application* _application; char* _response; }; OpenCommand::OpenCommand (Application* a) { _application = a; } void OpenCommand::Execute () { const char* name = AskUser() if(name != 0) { Document* document = new Document (name); _application->Add (document); document->open(); } }
// PasteCommand需要一个Document对象作为其接收者。该接收者将作为一个参数给PasteCommand的构造器。 class PasteCommand : public Command { public: PasteCommand(Document*); virtual void Execute(); private: Document* _document; }; PasteCommand::PasteCommand (Document* doc) { _document = doc; } void PasteCommand::Execute () { _document->Paste(); }
// 对于简单的不能取消和不需参数的命令,可以用一个类模板来参数化该命令的接收者。 // 我们将为这些命令定义一个模板子类SimpleCommand。用Receiver类型参数化SimpleCommand, // 并维护一个接收者对象和一个动作之间的绑定,而这一动作是用指向一个成员函数的指针存储的。 template <class Receiver> class SimpleCommand : public Command { public: typedef void (Receiver::* Action)(); SimpleCommand(Receiver* r, Action a):_receiver(r),_action(a){} virtual void Execute(); private: Action _action; Receiver* _receiver; }; // 构造器存储接收者和对应实例变量中的动作。Execute操作实施接收者的这个动作。 template <class Receiver> void simpleCommand<Receiver>::Execute () { (_receiver->*_action)(); } // 为创建一个调用Myclass类的一个实例上的Action的Command对象,仅需如下代码: Myclass* receiver = new Myclass; // ... Command* aCommand = new simpleCommand<Myclass>(receiver,&Myclass::Action); // ... aCommand->Execute ();
// MacroCommand管理一个子命令序列,它提供了增加和删除子命令的操作。 // 这里不需要显式的接收者,因为这些子命令已经定义了它们各自的接收者。 class MacroCommand : public Command { public: MacroCommand(); virtual ~MacroCommand(); virtual void Add(Command*); virtual void Remove(Command*); virtual void Execute(); private: List<Command*>* _cmds; }; // MacroCommand的关键是它的Execute成员函数。它遍历所有的子命令并调用其各自的Execute操作。 void MacroCommand::Execute () { ListIterator<Command*> i(_cmds); for (i.First(); !i.IsDone(); i.Next()) { Command *c = i.CurrentItem(); c->Execute(); } } // 注意,如果MacroCommand实现取消操作,那么它的子命令必须以相对于Execute的实现相反的顺序执行各子命令的取消操作。 // 最后,MacroCommand必须提供管理它的子命令的操作。MacroCommand也负责删除它的子命令。 void MacroCommand::Add (Command* c) { _cmds->Append(c); } void MacroCommand::Remove (Command* c) { _cmds->Remove(c); }
6、总结
命令模式将请求封装为对象,从而可以用不同的请求对客户进行参数化。
命令模式支持请求排队、支持撤销操作。
本文来自博客园,作者:流翎,转载请注明原文链接:https://www.cnblogs.com/hjx168/p/16219650.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?