设计模式——命令模式
转载来自:https://www.cnblogs.com/wzxNote/p/13305597.html
命令模式
模式定义
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
模式动机
- 敏捷开发的原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
UML类图
在该类图中,我们看到三个角色:
- Receiver接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的
- Command命令角色:需要执行的所有命令都在这里声明
- Invoker调用者角色:接收到命令,并执行命令
源码实现
- command.h
#include "chef.h" class Command { public: Command(Chef* chef); virtual ~Command(); virtual void ExcuteCmd(); protected: Chef* m_Chef; };
- chef.h
class Chef { public: Chef(); void KungPaoChicken(); void FishFlavoredShreddedPork(); void BigPlateChicken(); };
- chef.cpp
#include "chef.h" #include <iostream> Chef::Chef() { } void Chef::KungPaoChicken() { std::cout << "宫保鸡丁" << std::endl; } void Chef::FishFlavoredShreddedPork() { std::cout << "鱼香肉丝" << std::endl; } void Chef::BigPlateChicken() { std::cout << "大盘鸡" << std::endl; }
- kungpaochickencmd.h
#include "command.h" #include "chef.h" class KungPaoChickenCmd : public Command { public: KungPaoChickenCmd(Chef* chef); void ExcuteCmd() override; };
- kungpaochickencmd.cpp
#include "kungpaochickencmd.h" KungPaoChickenCmd::KungPaoChickenCmd(Chef* chef) :Command(chef) { } void KungPaoChickenCmd::ExcuteCmd() { m_Chef->KungPaoChicken(); }
- waiter.h
#include <list> #include <command.h> class Waiter { public: Waiter(); void AddCmd(Command* cmd); void DelCmd(Command* cmd); void Nodify(); private: std::list<Command*> m_CmdList; };
- waiter.cpp
#include "waiter.h" Waiter::Waiter() { } void Waiter::AddCmd(Command *cmd) { m_CmdList.push_back(cmd); } void Waiter::DelCmd(Command *cmd) { m_CmdList.remove(cmd); } void Waiter::Nodify() { for(auto cmd : m_CmdList) { if(cmd) cmd->ExcuteCmd(); } }
- main.cpp
#include <iostream> #include "fishflavoredshreddedporkcmd.h" #include "kungpaochickencmd.h" #include "bigplatechickencmd.h" #include "waiter.h" #include <memory> int main() { std::shared_ptr<Chef> chef = std::make_shared<Chef>(); Waiter waiter; std::shared_ptr<FishFlavoredShreddedPorkCmd> ffspc = std::make_shared<FishFlavoredShreddedPorkCmd>(chef.get()); std::shared_ptr<KungPaoChickenCmd> kpcc = std::make_shared<KungPaoChickenCmd>(chef); std::shared_ptr<BigPlateChickenCmd> bpcc = std::make_shared<BigPlateChickenCmd>(chef); waiter.AddCmd(ffspc.get()); waiter.AddCmd(kpcc.get()); waiter.AddCmd(bpcc.get()); // waiter.DelCmd(kpcc.get); waiter.Nodify(); return 0; }
- 运行结果
鱼香肉丝 宫保鸡丁 大盘鸡
优点
命令模式的优点
- 它能较容易的设计一个命令队列;
- 在需要的情况下,可以较容易的将命令计入日志;
- 允许接收请求的一方决定是否要否决请求;
- 可以容易的实现对请求的撤销和重做;
- 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易;
- 把请求一个操作的对象与知道怎么执行一个操作的对象分隔开;
缺点
模式的缺点
如果命令很多,Command类会很多,增加系统复杂性。
总结
参考来自:https://www.cnblogs.com/xuwendong/p/9814421.html
命令模式将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式主要解决的问题是在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合,这是命令模式的使用场景。
如果系统支持命令的撤销和恢复的话,可以考虑使用命令模式
命令模式的实现过程通过调用者调用 接受者执行命令,顺序:调用者→接受者→命令。