Java设计模式笔记之命令模式

概念

命令模式将“请求”封装成对象,这可以让你使用不同的请求、队列、或者日志请求来参数化其他对象。命令模式也支持撤销操作。

有时候在程序中需要在一个对象中处理很多个请求,这些请求对象没有实现统一的接口,需要写很多的判断语句加以区分不同的请求,然后执行相应的操作。命令模式提供了一种新的思路,通过创建一个新的对象命令对象,定义统一的方法名称,并且命令对象中有一个请求对象属性(组合)封装请求对象,在代码中调用命令对象统一的方法操作请求对象,不用写if语句区分不同的请求对象。

类图

命令模式将请求封装在一个对象中,允许代码像操作对象一样去操作不同的方法,传递并且在合适的时机去调用请求对象的方法。有时候需要执行一个请求,但又不知道具体是什么请求,命令模式可以通过命令对象封装请求,把命令对象当作参数传递,执行命令对象中的方法。这样代码中操作的就是统一的命令对象,就可以把代码规范化。

代码例子

在这我们以《headfirst设计模式》中的例子进行说明。有个遥控器有7个插槽,用来控制不同的电器,每个插槽对应两个按钮,开和关。遥控器有一个总的撤销按钮。如果遥控器的插槽有装置插入,按对应的开、关和撤销按钮就可以控制电器。下面是具体的代码实现。

package cn.lzz.hf.command;

/**
 * 命令对象接口
 * @author Administrator
 *
 */
public interface Command {
    
    /**
     * 执行请求
     */
    void execute();
    
    /**
     * 撤销请求
     */
    void undo();
}



package cn.lzz.hf.command;

/**
 * 电灯对象
 * @author Administrator
 *
 */
public class Light {
	public void on(){
		System.out.println("Light is on.");
	}
	public void off(){
		System.out.println("Light is off.");
	}
}

package cn.lzz.hf.command;

/**
 * 关灯命令对象
 * @author Administrator
 *
 */
public class LightOffCommand implements Command {
	private Light light;
	public LightOffCommand(Light light){
		this.light=light;
	}
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		light.off();
	}
	@Override
	public void undo() {
		// TODO Auto-generated method stub
		light.on();
	}
	

}

package cn.lzz.hf.command;

/**
 * 开灯命令对象
 * @author Administrator
 *
 */
public class LightOnCommand implements Command {
	private Light light;
	public LightOnCommand(Light light){
		this.light=light;
	}
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		light.on();
	}
	@Override
	public void undo() {
		// TODO Auto-generated method stub
		light.off();
	}
	

}

package cn.lzz.hf.command;

/**
 * 收音机对象
 * @author Administrator
 *
 */
public class Stereo {
	public void on(){
		System.out.println("Stereo is on");
	}
	public void off(){
		System.out.println("Stereo is off");
	}
	
}

package cn.lzz.hf.command;

/**
 * 关收音机命令对象
 * @author Administrator
 *
 */
public class StereoOffCommand implements Command {
	private Stereo stereo;
	public StereoOffCommand(Stereo stereo){
		this.stereo=stereo;
	}
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		stereo.off();
	}
	@Override
	public void undo() {
		// TODO Auto-generated method stub
		stereo.on();
	}
	

}

package cn.lzz.hf.command;

/**
 * 开收音机命令对象
 * @author Administrator
 *
 */
public class StereoOnCommand implements Command {
	private Stereo stereo;
	public StereoOnCommand(Stereo stereo){
		this.stereo=stereo;
	}
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		stereo.on();
	}
	@Override
	public void undo() {
		// TODO Auto-generated method stub
		stereo.off();
	}
	

}

package cn.lzz.hf.command;

/**
 * 空命令对象
 * @author Administrator
 *
 */
public class NoCommand implements Command {

	@Override
	public void execute() {
		// TODO Auto-generated method stub
	}

	@Override
	public void undo() {
		// TODO Auto-generated method stub
		
	}

}

package cn.lzz.hf.command;

import java.util.Stack;

/**
 * 遥控器对象
 * @author Administrator
 *
 */
public class RemoteControl {
	//打开按钮数组
	private Command[] onCommands;
	
	//关闭按钮数组
	private Command[] offCommands;
	
	//撤销命令栈
	private Stack<Command> undoCommandStack; 
	
	/**
	 * 初始化
	 */
	public RemoteControl(){
		onCommands=new Command[7];
		offCommands=new Command[7];
		Command tempCommand=new NoCommand();
		for(int i=0;i<7;i++){
			onCommands[i]=tempCommand;
			offCommands[i]=tempCommand;
		}
		undoCommandStack=new Stack<Command>();
	}
	
	/**
	 * 设置命令对象
	 * @param soltIndex
	 * @param onCommand
	 * @param offCommand
	 */
	public void setCommand(int soltIndex,Command onCommand,Command offCommand){
		onCommands[soltIndex]=onCommand;
		offCommands[soltIndex]=offCommand;
	}
	/**
	 * on
	 * @param soltIndex
	 */
	public void onButtonWasPressed(int soltIndex){
		onCommands[soltIndex].execute();
		//记录命令对象
		undoCommandStack.push(onCommands[soltIndex]);
	}
	/**
	 * off
	 * @param soltIndex
	 */
	public void offButtonWasPressed(int soltIndex){
		offCommands[soltIndex].execute();
		//记录命令对象
		undoCommandStack.push(offCommands[soltIndex]);
	}
	/**
	 * 撤销方法
	 */
	public void undoButtonWasPressed(){
		while(!undoCommandStack.isEmpty()){
			undoCommandStack.pop().undo();
		}
		
	}
	@Override
	public String toString() {
		StringBuilder stringBuilder=new StringBuilder();
		stringBuilder.append("\n--------------    Remote Control     ----------------\n");
		for(int i=0;i<onCommands.length;i++){
			stringBuilder.append("[solt "+i+"]"+onCommands[i].getClass().getName()
					+"         "+offCommands[i].getClass().getName()+"\n");
		}
		return stringBuilder.toString();
	}
	
}
package cn.lzz.hf.command;

/**
 * 测试代码
 * @author Administrator
 *
 */
public class RemoteControlTest {
	public static void main(String[] args) {
		//遥控器对象
		RemoteControl control=new RemoteControl();
		
		//电灯对象
		Light light=new Light();
		Command onLight=new LightOnCommand(light);
		Command offLight=new LightOffCommand(light);
		control.setCommand(0, onLight, offLight);
		
		//收音机对象
		Stereo stereo=new Stereo();
		Command onStereo=new StereoOnCommand(stereo);
		Command offStereo=new StereoOffCommand(stereo);
		control.setCommand(1, onStereo, offStereo);
		
		System.out.println("开灯-》关灯-》撤销");
		control.onButtonWasPressed(0);
		control.offButtonWasPressed(0);
		control.undoButtonWasPressed();
		
		System.out.println("关灯-》开灯-》撤销");
		control.offButtonWasPressed(0);
		control.onButtonWasPressed(0);
		control.undoButtonWasPressed();
		
		System.out.println("关闭收音机-》打开收音机-》撤销");
		control.offButtonWasPressed(1);
		control.onButtonWasPressed(1);
		control.undoButtonWasPressed();
		
		System.out.println("打开收音机-》关闭收音机-》撤销");
		control.onButtonWasPressed(1);
		control.offButtonWasPressed(1);
		control.undoButtonWasPressed();
		
		System.out.println("关灯-》打开收音机-》撤销");
		control.offButtonWasPressed(0);
		control.onButtonWasPressed(1);
		control.undoButtonWasPressed();
		
		
	}
}

执行结果

开灯-》关灯-》撤销
Light is on.
Light is off.
Light is on.
Light is off.
关灯-》开灯-》撤销
Light is off.
Light is on.
Light is off.
Light is on.
关闭收音机-》打开收音机-》撤销
Stereo is off
Stereo is on
Stereo is off
Stereo is on
打开收音机-》关闭收音机-》撤销
Stereo is on
Stereo is off
Stereo is on
Stereo is off
关灯-》打开收音机-》撤销
Light is off.
Stereo is on
Stereo is off
Light is on.

上面代码中,我们通过命令对象Command封装了Light和Stereo对象的开和关命令,在遥控器中可以调用参数对象Command,利用多态的特性模板化遥控器的代码,兼容不同的电器对象。如果需要增加新的电器,只需要创建相应的Command对象就可以实现,不用更改遥控器中的代码。

遥控器代码初始化时, 7个插槽设置了相同的空命令对象,这样在开、关按钮被按下的时候,不用判断插槽中是否有装置,也就是代码中不用判空。这是开发中常用的一中技巧。

总结

命令模式有以下几个优点     

1、命令模式通过命令对象把操作对象和请求对象解耦;

2、请求对象可以利用多态的特性复用具体的命令对象;

3、一个命令对象可以执行多个请求对象的具体操作;

4、增加一个具体的命令对象很容易。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值