一、 命令模式概述
命令模式定义:将一个请求封装为一个对象,使我们可以用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持撤销和恢复命令的操作。下面是一个典型的命令模式的类图。
命令模式引入命令对象,将发送者的请求封闭在命令对象中,再通过命令对象来调用接收者的方法,这样可以实现发送者和接收者的解耦。下面是一个典型的命令模式结构图
从上边的类图中可以看到,命令模式主要有以下角色
抽象命令(Command)角色:该角色声明一个给所有具体命令类的抽象接口,定义需要执行的命令;
具体命令(ConcreteCommand)角色:该角色定义一个接收者和行为之间的弱耦合,实现命令方法,并调用接收者的相应操作;
调用者(Invoker)角色:该角色负责调用命令对象执行请求;
接收者(Receiver)角色:该角色负责具体实施和执行一个请求。
一、 命令模式案例
例1、假设我们要用命令模式来设计一个自动售货机,那我们该怎么设计呢?为发简明起见,我们假设这种售货机只能销售可口可乐和芬达两种饮料。那么获取可口可乐的命令自然就是 GetCocacolaCmd() 而获取芬达的命令就是 GetFantaCmd() 了,显然这两个类都应该是抽象命令类的子类。这两个命令应该是由自动售货机(AutoVendingMachine)来执行的,为了使
售货机能缓存命令,我们引进 RecordCommand 类,该类内部用一个 vector来存储客户发来的命令。其实此程序结构非常简单,我就不多解释了,下面直接来看类图和源码…
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//自动售货机
class AutoVendingMachine
{
public:
void getCocaCola()
{
cout << "Get Coca-cola" << endl;
}
void getFanta()
{
cout << "Get Fanta" << endl;
}
};
//抽象命令类
class AbstractCommand
{
protected:
AutoVendingMachine *receiver;
public:
AbstractCommand(AutoVendingMachine *aMachine)
{
receiver = aMachine;
}
virtual void executeCmd() = 0;
};
//具体命令类:获取可口可乐类
class GetCocaColaCmd : public AbstractCommand
{
public:
GetCocaColaCmd(AutoVendingMachine *temp) : AbstractCommand(temp){}
virtual void executeCmd()
{
receiver->getCocaCola();
}
};
//具体命令类:获取芬达类
class GetFantaCmd : public AbstractCommand
{
public:
GetFantaCmd(AutoVendingMachine *temp) : AbstractCommand(temp){}
virtual void executeCmd()
{
receiver->getFanta();
}
};
//命令记录类
class RecordCommand
{
protected:
vector<AbstractCommand *> commandList;
public:
void sendCmd(AbstractCommand *temp)
{
commandList.push_back(temp);
cout << "Add a new command" << endl;
}
//通知执行
void notify()
{
vector<AbstractCommand *>::iterator iter = commandList.begin();
while(iter != commandList.end())
{
(*iter)->executeCmd();
iter++;
}
}
};
int main()
{
AutoVendingMachine *aMachine=new AutoVendingMachine();
AbstractCommand *cmd_1= new GetCocaColaCmd(aMachine);
AbstractCommand *cmd_2=new GetFantaCmd(aMachine);
RecordCommand *rCommand = new RecordCommand();
//发送命令
rCommand->sendCmd(cmd_1);
rCommand->sendCmd(cmd_2);
//通知系统执行命令
rCommand->notify();
cout << endl;
return 0;
}
例 2、假设现在某公司要生产一种遥控机器人,研发部的工程师要负责该机器人及其遥控器的软件系统设计。为了简明起见,现假设该机器只有几种简单的功能:启动、停止、工作(抽象的工作,具体的不用实现)。显然这系统很适合用命令模式,因此该系统至少应该有以下功能类:Controller(遥控器类),负责控制机器人执行客户选择的命令;AbstractCommand(抽象命令类),定义执行命令的抽象方法execute(),具体实现由子类完成;StartRobotCmd(启动机器人类)、StopRobotCmd(停止机器人类)、RobotWorkCmd(机器人工作类),这三个类都是AbstractCommand的子类。其类图和源码如下
1、机器人类
package cn.org.lion;
public class Robot {
public void start()
{
System.out.println("Hello, my name is Lion, I'm started");
}
public void stop()
{
System.out.println("I'm stopped");
}
public void work()
{
System.out.println("Your wish is my command, what do you want me to do ?");
}
}
2、抽象命令类
package cn.org.lion;
public interface AbstractCommand {
public void executeCmd();
}
3、启动机器人类
package cn.org.lion;
public class StartRobotCmd implements AbstractCommand{
private Robot robot;
public StartRobotCmd()
{
robot = new Robot();
}
public void executeCmd()
{
robot.start();
}
}
4、机器人工作类
package cn.org.lion;
public class RobotWorkCmd implements AbstractCommand{
private Robot robot;
public RobotWorkCmd()
{
robot = new Robot();
}
public void executeCmd()
{
robot.work();
}
}
5、停止机器人类
package cn.org.lion;
public class StopRobotCmd implements AbstractCommand{
private Robot robot;
public StopRobotCmd()
{
robot = new Robot();
}
public void executeCmd()
{
robot.stop();
}
}
6、遥控器类
package cn.org.lion;
public class Controller {
private AbstractCommand startCmd, stopCmd, workCmd;
public Controller(AbstractCommand startCmd, AbstractCommand stopCmd, AbstractCommand workCmd)
{
this.startCmd = startCmd;
this.stopCmd = stopCmd;
this.workCmd = workCmd;
}
public void startRobot()
{
startCmd.executeCmd();
}
public void stopRobot()
{
stopCmd.executeCmd();
}
public void robotWork()
{
workCmd.executeCmd();
}
}
7、客户端测试类
package cn.org.lion;
public class ClientTest {
public static void main(String args[])
{
AbstractCommand startCmd, stopCmd, workCmd;
startCmd = new StartRobotCmd();
stopCmd = new StopRobotCmd();
workCmd = new RobotWorkCmd();
Controller controller = new Controller(startCmd, stopCmd, workCmd);
controller.startRobot();
controller.robotWork();
controller.stopRobot();
}
}
三、小结
命令模式降低系统的耦合度,因为请求的发出者和接收者之间没有直接引用关系,所以它们之间没有耦合;增加新的命令很方便,不影响其他类。但是如果系统要实现的命令很多,那么就要写很多的具体命令类。