在开发过程中,我可能会需要向某些对象发送一些请求,但是我们不知请求的具体接收者是谁,也不知道被请求的操作是那个,我们只知道在程序运行中指定具体的请求接收者即可。打个比方,电视遥控器,我们只需要知道按那个按钮能够打开电视、关闭电视和换台即可,并不需要知道是怎么开电视、关电视和换台的。对于这种情况,我们可以采用命令模式来进行设计。
一、基本定义
命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式支持可撤销的操作。
命令模式可以对发送者额接受者完全解耦,发送者也接收者之间并没有直接的联系,发送者只需要知道如何发送请求,不需要关心请求是如何完成了。这就是命令模式,命令模式将方法调用给封装起来了。
二、模式结构
从上图可以看出命令模式包含如下几个角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,是的发送者只需要知道如何发送命令即可,不需要命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。
三、模式实现
这里以电视机为例。电视剧是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。
UML图:
Command.h代码如下:
#include "stdafx.h"
#include <iostream>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
using namespace boost;
//命令模式可以使请求者和接受者完全解耦
//这里以遥控器请求电视换台为例进行讲解
//遥控器的按钮都是命令,遥控器发送命令时
//不需要关注电视台能否接受并执行命令
//遥控器上的命令基类
class Command
{
public:
virtual void execute() = 0;
};
//遥控器
class Telecontroller
{
private:
shared_ptr<Command> __m_Switch1;//切换到频道1命令
shared_ptr<Command> __m_Switch2;//切换到频道2命令
shared_ptr<Command> __m_Switch3;//切换到频道3命令
public:
Telecontroller(shared_ptr<Command>,shared_ptr<Command>,shared_ptr<Command>);
void switchTo1(){__m_Switch1->execute();}
void switchTo2(){__m_Switch2->execute();}
void switchTo3(){__m_Switch3->execute();}
};
//电视机
class Television
{
public:
void switchTo1(){std::cout << "频道1" << std::endl;}
void switchTo2(){std::cout << "频道2" << std::endl;}
void switchTo3(){std::cout << "频道3" << std::endl;}
};
class Command1 : public Command
{
public:
Command1(){}
Command1(shared_ptr<Television> tv){__m_TV = tv;}
virtual void execute()
{
__m_TV->switchTo1();
}
private:
shared_ptr<Television> __m_TV;
};
class Command2 : public Command
{
public:
Command2(){}
Command2(shared_ptr<Television> tv){__m_TV = tv;}
virtual void execute()
{
__m_TV->switchTo2();
}
private:
shared_ptr<Television> __m_TV;
};
class Command3 : public Command
{
public:
Command3(){}
Command3(shared_ptr<Television> tv){__m_TV = tv;}
virtual void execute()
{
__m_TV->switchTo3();
}
private:
shared_ptr<Television> __m_TV;
};
Command.cpp代码如下:
#include "stdafx.h"
#include <iostream>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include "Command.h"
using namespace boost;
//命令模式可以使请求者和接受者完全解耦
//这里以遥控器请求电视换台为例进行讲解
//遥控器的按钮都是命令,遥控器发送命令时
//不需要关注电视台能否接受并执行命令
Telecontroller::Telecontroller(shared_ptr<Command> c1,shared_ptr<Command> c2,shared_ptr<Command> c3)
{
__m_Switch1 = c1;
__m_Switch2 = c2;
__m_Switch3 = c3;
}
void testCommandMode()
{
shared_ptr<Television> tv = make_shared<Television>();
auto c1 = make_shared<Command1>(tv);
auto c2 = make_shared<Command2>(tv);
auto c3 = make_shared<Command3>(tv);
auto control = make_shared<Telecontroller>(c1,c2,c3);
control->switchTo1();
control->switchTo2();
control->switchTo3();
}