我对命令模式的理解

一.概念

命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。即,命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。

二.举例子

电视机遥控器,每一个按钮都代表着一个命令,所以很容易想到,电视机是一个命令接收器,遥控器就是一个集成了很多按钮的命令发送器。那么现在实现几个常用功能,电视机的开机,电视机的关机,电视机频道增大,电视机频道减小,撤销上一次操作,恢复撤销的操作。

/**
 * 命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
 * 应用场景
 * 在下面的情况下应当考虑使用命令模式:
 * 1)使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。
 * 2)需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,
 * 而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。
 * 3)系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。
 * 4)如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
 */
public class CommandTest {
	
	class TV {
		private int number;		//当前频道,总共50个频道(0-49)
		private boolean state;	//电视机的状态
		public TV(int number) {
			this.number = number;//设置当前频道;
			this.state = false;//当前状态
		}
		public void changeStateOpen() {
			this.state = true;
			System.out.println("开启电视机,当前频道为"+this.number);
		}
		public void changeStateClose() {
			this.state = false;
			System.out.println("关闭电视机");
		}
		public void increaseNumber() {
			this.number = (this.number + 1) % 50;
			System.out.println("当前频道为"+this.number);
		}
		public void decreaseNumber() {
			this.number = (this.number + 49) % 50;
			System.out.println("当前频道为"+this.number);
		}
		public int getNumber() {
			return number;
		}
		public boolean isState() {
			return state;
		}
	}
	
	interface Command {
		public void excute();//执行操作
		public void undo();//撤销操作
		public void redo();//恢复操作
	}
	class TurnOnTV implements Command {
		private TV tv;
		public TurnOnTV(TV tv) {
			this.tv = tv;
		}
		@Override
		public void excute() {
			this.tv.changeStateOpen();
		}

		@Override
		public void undo() {
			this.tv.changeStateClose();
		}

		@Override
		public void redo() {
			this.tv.changeStateOpen();
		}
	}
	class TurnOffTV implements Command {
		private TV tv;
		public TurnOffTV(TV tv) {
			this.tv = tv;
		}
		@Override
		public void excute() {
			this.tv.changeStateClose();
		}

		@Override
		public void undo() {
			this.tv.changeStateOpen();
		}

		@Override
		public void redo() {
			this.tv.changeStateClose();
		}
	}
	class TurnIncreaseNumber implements Command {
		private TV tv;
		public TurnIncreaseNumber(TV tv) {
			this.tv = tv;
		}
		@Override
		public void excute() {
			if(this.tv.isState()){
				this.tv.increaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}
		@Override
		public void undo() {
			if(this.tv.isState()) {
				this.tv.decreaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}

		@Override
		public void redo() {
			if(this.tv.isState()){
				this.tv.increaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}
	}
	class TurnDecreaseNumber implements Command {
		private TV tv;
		public TurnDecreaseNumber(TV tv) {
			this.tv = tv;
		}
		@Override
		public void excute() {
			if(this.tv.isState()) {
				this.tv.decreaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}
		@Override
		public void undo() {
			if(this.tv.isState()){
				this.tv.increaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}

		@Override
		public void redo() {
			if(this.tv.isState()) {
				this.tv.decreaseNumber();
			}else {
				System.err.println("电视机未开");
			}
		}
	}
	class NoCommand implements Command {
		@Override
		public void excute() {}
		@Override
		public void undo() {}
		@Override
		public void redo() {}
	}
	class RemotrControl {
		private Command[] command;
		private Command undoCommand;
		private Command redoCommand;
		
		public RemotrControl() {
			command = new Command[4];//初始化遥控器有6个按钮
			for(int i=0; i < 4; i++) {
				command[i] = new NoCommand();//初始化成空命令
			}
			undoCommand = new NoCommand();//初始化撤销命令
			redoCommand = new NoCommand();//初始化恢复命令
		}
		
		public void setCommand(int slot, Command command) {
			this.command[slot] = command;
		}
		
		public void runCommand(int slot) {
			this.command[slot].excute();
			this.undoCommand = this.command[slot];
		}
		public void undoCommand() {
			this.undoCommand.undo();
			this.redoCommand = this.undoCommand;
		}
		public void redoCommand() {
			this.redoCommand.redo();
		}
	}
	
	
	public static void main(String[] args) {
		//为电视机添加遥控器功能
		TV tv = new CommandTest().new TV(4);
		RemotrControl control = new CommandTest().new RemotrControl();
		control.setCommand(0, new CommandTest().new TurnOnTV(tv));
		control.setCommand(1, new CommandTest().new TurnOffTV(tv));
		control.setCommand(2, new CommandTest().new TurnIncreaseNumber(tv));
		control.setCommand(3, new CommandTest().new TurnDecreaseNumber(tv));
		//测试按钮命令
		control.runCommand(0);
		control.runCommand(2);
		control.runCommand(2);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.runCommand(3);
		control.undoCommand();
		control.runCommand(1);
		control.runCommand(3);
	}
}

运行结果:



三.总结

应用场景
在下面的情况下应当考虑使用命令模式:
使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。
需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,
而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。
系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。
如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。



更多参考

http://blog.csdn.net/hguisu/article/details/7549895

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值