命令模式

一、      命令模式概述

  命令模式定义:将一个请求封装为一个对象,使我们可以用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持撤销和恢复命令的操作。下面是一个典型的命令模式的类图。

  命令模式引入命令对象,将发送者的请求封闭在命令对象中,再通过命令对象来调用接收者的方法,这样可以实现发送者和接收者的解耦。下面是一个典型的命令模式结构图


从上边的类图中可以看到,命令模式主要有以下角色

抽象命令(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();
	}
}

三、小结

    命令模式降低系统的耦合度,因为请求的发出者和接收者之间没有直接引用关系,所以它们之间没有耦合;增加新的命令很方便,不影响其他类。但是如果系统要实现的命令很多,那么就要写很多的具体命令类。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Storm-Shadow

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值