命令模式

实例场景:

1、餐馆点菜吃饭:当我们在餐馆进行点菜的时候,一般我们会进行点菜,然后服务员下订单,然后厨师根据订单进行炒菜,最后摆在我们面前的就是一盘美味佳肴了。

2、领导下命令:领导要员工做事的时候,一般是把事情告诉秘书或行政人员,然后由她们把领导安排的事情下发到员工。

3、当我们想要听音乐,只要我们按下播放键盘,相应的音乐就自动播放了。

以上场景中我们都使用了一种设计模式:命令模式

命令模式把一个请求或者操作封装到一个对象中。命令模式运行系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

命令模式中是把一个命令封装为一个对象。

命令模式的角色

客户角色:创建一个具体命令对象,并确定其接受者

命令角色:声明一个给所有具体命令类的抽象接口,这是一个抽象角色,通常由一个接口或抽象类实现。

具体命令角色:定义接收者和行为之间的弱耦合,实现execute方法,负责调用接收者的相应操作。

请求者角色:负责调用命令对象执行请求。

接收者角色:负责具体实施和执行一个请求。

在上面的实例场景中,场景分析如下:

1、餐馆点菜,我们相当与一个客户角色,我们点菜就是发送命令,不同的人或有不同的命令请求,就应该把命令设计为抽象类,用户发出的请求就是具体的命令,服务员就是一个请求者,她把命令也就是客户的订单给接受者厨师,厨师只要照着菜单做菜,做好后给客户即可,客户不用去管菜是怎样做出来的,只要发送一个命令,然后得到自己的结果就可以了。

2、领导下命令:我是老总,我只管发个命令,至于这个命令发给谁,谁执行,关我P事,我发钱请人不是为了给自己找麻烦。你是负责事情的员工,你的天职是做好上级交给你的任务,踏踏实实,不要知道太多,不要八卦,不要问太多了。Client对象是发布命令的。Invoker对象是传递命令的,就是跑腿的。Receiver是受气包,底层最累的程序员,负责干活吧

3、一个Mp3。你按了一个播放键盘,就播放了。这就可以算是命令模式的一种。 你是Client ,按键是Invoker,mp3是Receiver,播放就是一个命令Command对象。

命令模式的好处

◆很容易构造一个命令队列

◆记录相关的命令日志

◆增加命令的状态,实现命令的撤销和重做

◆允许接受请求的一方决定是否可做

◆新的命令轻而易举可以加入其中

缺点可能会有过多的具体命令类存在

场景代码实现:

package cn.com.command;
//声明一个命令角色
public interface Command {
	public void execute();
}

package cn.com.command;
//定义一个接收者,相当与一个厨师
//负责具体实施和执行一个请求
public class Recevier {
	public void doAction(){
		System.out.println("客户发订单了,我要炒菜了");
	}
}

package cn.com.command;
//具体的命令角色,负责调用接收者相应的操作
public class ConcreteCommand implements Command{
	private Recevier recevier;
	public ConcreteCommand(Recevier recevier){
		this.recevier=recevier;
	}
	
	@Override
	public void execute() {
		recevier.doAction();
	}
}
package cn.com.command;
//定义一个请求者角色,
//负责调用命令对象,执行请求
public class Invoker {
	private Command command;
	public Invoker(Command command){
		this.command=command;
	}
	
	public void doInvokerAction(){
		command.execute();
	}
}

package cn.com.command;
//创建客户角色,客户进行点菜
public class Client {
	public static void main(String[] args) {
		//生成一个具体的厨师角色
		Recevier recevier=new Recevier();
		//生成一个菜单命令对象
		Command command=new ConcreteCommand(recevier);
		//服务员把菜单给厨师,厨师具体实施,进行炒菜
		Invoker invoker=new Invoker(command);
		invoker.doInvokerAction();
		//在整个应用场景中,实际上是请求者调用具体命令对象,具体命令对象调用接收者
	}
}

代码输出:

客户发订单了,我要炒菜了
在整个应用场景中,实际上是请求者调用具体命令对象,具体命令对象调用接收者

JUnit框架中,运用了我们的命令模式:

用户编写测试用例TestCase,把这些测试用例组成请求(可能是一个或者多个),发送到JUnit,然后由JUnit执行,最后报告详细测试结果包括执行的时间,错误方法,错误位置等。这样测试用例的开发人员就不需要知道请求TestCase的具体操作信息,仅把它当作一种命令来执行,然后把执行测试结果发给测试人员。这样就使JUnit框架和TestCase的开发人员独立开来,使得请求的一方不必知道接收请求一方的详细信息,更不必知道是怎样被接收,以及怎样被执行的,实现系统的松藕合。

使用命令模式后给JUnit系统的架构带来的效果

a、将实现请求的一方(TestCase开发)和调用一方JUnit进行解耦

b、使新的TestCase很容易加入,无需改变已有的类,只需继承TestCase类即可,这样方便了测试人员

c、可以将多个TestCase进行组合成一个复合命令,TestSuit就是它的复合命令,使用了组合模式

d、容易把请求的TestCase组成请求队列,这样使接收请求的一方JUnit框架,容易决定是否执行请求,一旦发现测试用例失败或者错误可以立即停止进行报告

简易理解场景模拟二:我们看电视,经常用到遥控,遥控上有电视开机、关机、切换频道命令等,用户按下相应的命令,电视就会执行相应的操作,我们把这个场景用命令模式来设计解决。

在这个场景中,电视机就是一个命令接收者,它接收到命令后执行相应的操作,遥控器就是命令请求者,当然是由用户去按遥控器上的按键,来请求命令,开机、关机、切换频道就是具体的命令,示意图如下:



从上图可以看出:遥控器操纵打开电视、关闭电视、切换频道等一系列命令,而这些命令来操纵电视。请求者操纵的是命令角色,而命令角色操纵的是命令接收者,下面我们编码来实现它:

定义命令接收者,电视

/**
 * 定义一个命令接收者
 * @author dell
 *
 */
public class TV {
	/**
	 * 打开电视
	 */
	public void turnOn(){
		System.out.println("打开电视");
	}
	
	/**
	 * 关闭电视
	 */
	public void turnOff(){
		System.out.println("关闭电视");
	}
	
	/**
	 * 更换电视频道
	 * @param channel
	 */
	public void changeChannel(int channel){
		System.out.println("你选择更换的频道为:"+channel);
	}
}
定义一个抽象的命令角色:

public interface Command {
	public void execute();
}
定义打开电视具体命令:

/**
 * 定义一个具体的命令角色,打开电视命令,直接操纵接收者
 * @author dell
 *
 */
public class CommandOn implements Command{
	//由命令操作接收者
	private TV tv;
	
	public CommandOn(TV tv){
		this.tv=tv;
	}
	
	@Override
	public void execute() {
		tv.turnOn();
	}
}
定义关闭电视命令:

/**
 * 定义一个具体的命令角色,关闭电视命令,直接操纵接收者
 * @author dell
 *
 */
public class CommandOff implements Command{
	//由命令操作接收者
	private TV tv;
	
	public CommandOff(TV tv){
		this.tv=tv;
	}
	
	@Override
	public void execute() {
		tv.turnOff();
	}
}
定义切换频道命令:

/**
 * 定义一个具体的命令角色,切换频道命令,直接操纵接收者
 * @author dell
 *
 */
public class CommandChange implements Command{
	//由命令操作接收者
	private TV tv;
	private int channel;
	
	public CommandChange(TV tv,int channel){
		this.tv=tv;
		this.channel=channel;
	}
	
	@Override
	public void execute() {
		tv.changeChannel(channel);
	}
}
定义遥控器,请求者:

/**
 * 定义一个请求者角色,相当于模拟场景中的遥控器,请求者角色直接控制命令
 * @author dell
 *
 */
public class Control {
	//因为用户在客户端调用的时候,只需要创建一个遥控器请求即可,所以这里可以将所有的命令实现类的引用传入进来
	private Command commandOn,commandOff,commandChange;
	
	public Control(Command commandOn,Command commandOff,Command commandChange){
		this.commandOn=commandOn;
		this.commandOff=commandOff;
		this.commandChange=commandChange;
	}

	public void turnOn(){
		commandOn.execute();
	}
	
	public void turnOff(){
		commandOff.execute();
	}
	
	public void changeChannel(){
		commandChange.execute();
	}
}
客户端测试:

/**
 * 测试命令模式
 * 角色:
 * 命令角色(抽象类或接口)
 * 具体命令角色(包含一个接收者的引用,因为是由具体命令操纵命令接受者)
 * 请求者角色(包含一个命令角色的引用,因为是由请求者发出命令)
 * 命令接受者
 * @author dell
 *
 */
public class Client {
	public static void main(String[] args) {
		//定义一个命令接收者(电视)
		TV tv=new TV();
		//定义一系列命令,例如打开电视、关闭电视、切换电视频道等
		Command commandOn=new CommandOn(tv);
		Command commandOff=new CommandOff(tv);
		Command commandChange=new CommandChange(tv,5);
		//客户对遥控器发出相应命令,客户只需要定义一个请求角色,即可获得所有所操控的命令,相当于只要一个遥控器
		Control control=new Control(commandOn,commandOff,commandChange);
		control.turnOn();
		control.turnOff();
		control.changeChannel();
	}
}

代码输出:

打开电视
关闭电视
你选择更换的频道为:5

这样,客户只管操纵请求者了,至于命令是怎么传达的跟客户端没什么关系,客户也不需要知道这些细节,用户只需拿遥控器按下相应的操作,电视接收到命令,给我执行相应的结果就是了,对于命令模式,是不是又加深了一些理解呢!!记住:请求者-->命令-->接收者

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值