C++设计模式—命令模式

产生背景

对一个对象要进行很多动作,每个动作就是一个命令。在原有的逻辑中,需要在客户端写出许多分支语句,针对每个动作,调用该对象的成员函数。每增加一个动作,都需要在客户端和对象类中修改代码违背了高内聚,低耦合的原则。因此,对于这种情况就可以使用命令模式。

命令模式概述

定义

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求队列或者记录请求日志,可以提供命令的撤销和恢复功能。它属于行为型模式

UML图

角色

  • 客户(Client):创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
  • 命令(Command):声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
  • 具体命令(ConcreteCommand):定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收者的相应操作。Execute()方法通常叫做执行方法。
  • 调用者(Invoker):负责调用命令对象执行请求,相关的方法叫做行动方法。常会持有命令对象,可以持有很多的命令对象。
  • 接收者(Receiver):负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

举例:

#include <iostream>
#include <vector>
using namespace std;


// 烤肉师傅(接收者)
class RoastCook
{
public:
	void MakeMutton() { cout << "烤羊肉" << endl; }
	void MakeChickenWing() { cout << "烤鸡翅" << endl; }
};


// 抽象命令类
class Command
{
public:
	Command(RoastCook* temp) { receiver = temp; }
	virtual void ExecuteCmd() = 0;

protected:
	RoastCook* receiver;//包含接收者
};

// 烤羊肉命令
class MakeMuttonCmd : public Command
{
public:
	MakeMuttonCmd(RoastCook* temp) : Command(temp) {}
	virtual void ExecuteCmd() { receiver->MakeMutton(); }//调用接收者执行相应的具体命令
};

// 烤鸡翅命令
class MakeChickenWingCmd : public Command
{
public:
	MakeChickenWingCmd(RoastCook* temp) : Command(temp) {}
	virtual void ExecuteCmd() { receiver->MakeChickenWing(); }
};

// 服务员类(调用者)
class Waiter
{
public:
	void SetCmd(Command* temp);

	// 通知执行
	void Notify();
protected:
	vector<Command*> m_commandList;
};

void Waiter::SetCmd(Command* temp)
{
	m_commandList.push_back(temp);
	cout << "增加订单" << endl;
}

void Waiter::Notify()
{
	vector<Command*>::iterator it;
	for (it = m_commandList.begin(); it != m_commandList.end(); ++it)
	{
		(*it)->ExecuteCmd();
	}
}

int main()
{
	// 店里添加烤肉师傅、菜单、服务员等顾客
	RoastCook* cook = new RoastCook();
	Command* cmd1 = new MakeMuttonCmd(cook);
	Command* cmd2 = new MakeChickenWingCmd(cook);
	Waiter* waitess = new Waiter();

	// 点菜
	waitess->SetCmd(cmd1);
	waitess->SetCmd(cmd2);

	// 服务员通知
	waitess->Notify();
	return 0;

}

在这里插入图片描述

优点

  • 降低系统的耦合度:Command模式将调用操作的对象与知道如何实现该操作的对象解耦。发布者只需要发布命令就可以,无需知道执行者是谁,发布者和执行者可以独立的进行修改
  • Command是头等的对象。它们可像其他的对象一样被操纵和扩展。
  • 组合命令:你可将多个命令装配成一个组合命令,即可以比较容易地设计一个命令队列和宏命令。一般说来,组合命令是Composite模式的一个实例。
  • 增加新的Command很容易,因为这无需改变已有的类。
  • 可以方便地实现对请求的Undo和Redo。系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。

举例:

假设有一个快餐店,而我是该餐厅的点餐服务员,那么我一天的工作应该是这样的:当某位客人点餐或者打来订餐电话后,我会把他的需求都写在清单上,然后交给厨房,客人不用关心是哪些厨师帮他炒菜。我们餐厅还可以满足客人需要的定时服务,比如客人可能当前正在回家的路上,要求 1个小时后才开始炒他的菜,只要订单还在,厨师就不会忘记。客人也可以很方便地打电话来撤销订单。另外如果有太多的客人点餐,厨房可以按照订单的顺序排队炒菜。这些记录着订餐信息的清单,便是命令模式中的命令对象。

缺点

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

适用场景

  • 需要在不同的时间制定请求、将请求排队
  • 系统需要支持命令的撤销
  • 如果要将系统中所有的数据更新到日志里。以便在系统崩溃时,可以根据日志读回所有的数据更新命令

猜你喜欢

转载自blog.csdn.net/qq_43313035/article/details/90115799