设计模式之命令模式

我们都知道餐厅是怎么样工作的:顾客下订单,招待拿了订单放在柜台,然后厨师根据订单准备餐点。

详细的来说,顾客是一个Client,takeOrder(),相当于setCommand(),订单是Command有orderUp()接口,女招待是一个Invoker,调用orderUp(),相当于execute(),最后厨师是Receiver。

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

上个类图:


---------------------------------------

遥控器是典型的命令模式的应用。

我们打算将遥控器的每个插槽对应到一个命令就让遥控器变成调用者。当按下按钮,响应命令对象的excute()会被调用,其结果就是,接受者的动作被调用。

我们假设有living room light,kitchen light,Stereo, ceiling fan等,有 on ,off按钮,还有个撤销的按钮

有这么些个实物类:

public class Light {
	private String location;
	
	public Light(String str){
		this.location=str;
	}
	
	public void on(){
		System.out.println(location+" light is on");
	}
	
	public void off(){
		System.out.println(location+" light is off");
	}

}

public class Stereo {
	private String location;
	
	public Stereo(String str){
		this.location=str;
	}
	public void on(){
		System.out.println(location+" stereo is on");
	}
	
	public void off(){
		System.out.println(location +" stereo is off");
	}
	
	public void setCd(){
		System.out.println("stereo is set for cd input");
	}
	
	public void setVolume(int i){
		System.out.println("stereo volume set to "+i);
	}

}

等等。。。。。。。。


实现遥控器:

public class RemoteControlWithUndo {
	Command[] onCommands;
	Command[] offCommands;
	Command undoCommand;
	
	public RemoteControlWithUndo(){
		onCommands=new Command[7];
		offCommands=new Command[7];
		
		Command noCommand=new NoCommand();
		for(int i=0;i<7;i++){
			onCommands[i]=noCommand;
			offCommands[i]=noCommand;
		}
		undoCommand=noCommand;
	}
	
	public void setCommand(int slot,Command onCommand,Command offCommand){
		onCommands[slot]=onCommand;
		offCommands[slot]=offCommand;
	}
	
	public void onButtonWasPushed(int slot){
		onCommands[slot].execute();
		undoCommand=onCommands[slot];
	}
	
	public void offButtonWasPushed(int slot){
		offCommands[slot].execute();
		undoCommand=offCommands[slot];
	}
	
	public void undoButtonWasPushed(){
		undoCommand.undo();
	}
	
	public String toString(){
		StringBuffer stringBuffer=new StringBuffer();
		stringBuffer.append("\n-----Remote Control With Undo----\n");
		for(int i=0;i<onCommands.length;i++){
			stringBuffer.append("[slot "+i+"]"+onCommands[i].getClass().getName()
					+"  "+offCommands[i].getClass().getName()+"\n");
		}
		stringBuffer.append("[undo] "+undoCommand.getClass().getName()+"\n");
		return stringBuffer.toString();
	}

}
Command是接口:

public interface Command {
	public void execute();
	public void undo();

}


然后各种命令:

public class LightOnCommand implements Command{
	
	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();
	}

}

public class LightOffCommand implements Command{
	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();
	}
	
	

}

public class StereoOnCommand implements Command{
	Stereo stereo;
	public StereoOnCommand(Stereo stereo){
		this.stereo=stereo;
	}
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		stereo.on();
		stereo.setCd();
		stereo.setVolume(11);
	}
	@Override
	public void undo() {
		// TODO Auto-generated method stub
		stereo.off();
	}
	
	

等等。。。。。。。。。。。。

特别的是,NoCommand类是空对象的例子,个人感觉蛮有用的

public class NoCommand implements Command{

	@Override
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("Not Support Command");
	}

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


}

测试程序:

public class RemoteLoader {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	
		RemoteControlWithUndo remoteControlWithUndo=new RemoteControlWithUndo();
		
		Light livingroomLight=new Light("living room");
		Light kitchenLight=new Light("kitchen");
		CeilingFan ceilingFan=new CeilingFan("living room");
		Stereo stereo=new Stereo("living room");
		
		LightOnCommand livingroomLightOn=new LightOnCommand(livingroomLight);
		LightOffCommand livingroomLightOff=new LightOffCommand(livingroomLight);
		LightOnCommand kitchenLightOn=new LightOnCommand(kitchenLight);
		LightOffCommand kitchenLightOff=new LightOffCommand(kitchenLight);
		
		CeilingFanOnCommand ceilingFanOn=new CeilingFanOnCommand(ceilingFan);
		CeilingFanOffCommand ceilingFanOff=new CeilingFanOffCommand(ceilingFan);
		
		StereoOnCommand stereoOn=new StereoOnCommand(stereo);
		StereoOffCommand stereoOff=new StereoOffCommand(stereo);
		


		remoteControlWithUndo.setCommand(0, livingroomLightOn, livingroomLightOff);
		remoteControlWithUndo.setCommand(1, kitchenLightOn, kitchenLightOff);
		remoteControlWithUndo.setCommand(2, ceilingFanOn, ceilingFanOff);
		remoteControlWithUndo.setCommand(3, stereoOn, stereoOff);
		
		System.out.println(remoteControlWithUndo);
		
		remoteControlWithUndo.onButtonWasPushed(1);
		remoteControlWithUndo.undoButtonWasPushed();
		System.out.println(remoteControlWithUndo);
		remoteControlWithUndo.offButtonWasPushed(1);
		System.out.println(remoteControlWithUndo);

	}

}


结果:

-----Remote Control With Undo----
[slot 0]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 1]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 2]remoteControl.CeilingFanOnCommand  remoteControl.CeilingFanOffCommand
[slot 3]remoteControl.StereoOnCommand  remoteControl.StereoOffCommand
[slot 4]remoteControl.NoCommand  remoteControl.NoCommand
[slot 5]remoteControl.NoCommand  remoteControl.NoCommand
[slot 6]remoteControl.NoCommand  remoteControl.NoCommand
[undo] remoteControl.NoCommand

kitchen light is on
kitchen light is off

-----Remote Control With Undo----
[slot 0]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 1]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 2]remoteControl.CeilingFanOnCommand  remoteControl.CeilingFanOffCommand
[slot 3]remoteControl.StereoOnCommand  remoteControl.StereoOffCommand
[slot 4]remoteControl.NoCommand  remoteControl.NoCommand
[slot 5]remoteControl.NoCommand  remoteControl.NoCommand
[slot 6]remoteControl.NoCommand  remoteControl.NoCommand
[undo] remoteControl.LightOnCommand

kitchen light is off

-----Remote Control With Undo----
[slot 0]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 1]remoteControl.LightOnCommand  remoteControl.LightOffCommand
[slot 2]remoteControl.CeilingFanOnCommand  remoteControl.CeilingFanOffCommand
[slot 3]remoteControl.StereoOnCommand  remoteControl.StereoOffCommand
[slot 4]remoteControl.NoCommand  remoteControl.NoCommand
[slot 5]remoteControl.NoCommand  remoteControl.NoCommand
[slot 6]remoteControl.NoCommand  remoteControl.NoCommand
[undo] remoteControl.LightOffCommand

补上测试了slot=0-4,也就是包含NoCommand的时候:

living room light is on
living room light is off
kitchen light is on
kitchen light is off
living room celling fan is on
living room celling fan is off
living room stereo is on
stereo is set for cd input
stereo volume set to 11
living room stereo is off
Not Support Command
Not Support Command

Party模式,使用宏命令:

public class MacroCommand implements Command{
	Command[]commands;
	
	public MacroCommand(Command[]commands){
		this.commands=commands;	
	}

	@Override
	public void execute() {
		// TODO Auto-generated method stub
		for(int i=0;i<commands.length;i++)
			commands[i].execute();
	}

	@Override
	public void undo() {
		// TODO Auto-generated method stub
		for(int i=0;i<commands.length;i++)
			commands[i].undo();
	}

}

测试类加入:

Command[]partyOn={livingroomLightOn,kitchenLightOn,ceilingFanOn,stereoOn};
		Command[]partyOff={livingroomLightOff,kitchenLightOff,ceilingFanOff,stereoOff};
		
		MacroCommand partyOnMacro=new MacroCommand(partyOn);
		MacroCommand partyOffMacro=new MacroCommand(partyOff);

然后setCommand
在测试:

		System.out.println("----Pushing Macro On-----");
		remoteControl.onButtonWasPushed(5);
		System.out.println("-----Pushing Macro Off-----");
		remoteControl.offButtonWasPushed(5);

结果:

----Pushing Macro On-----
living room light is on
kitchen light is on
living room celling fan is on
living room stereo is on
stereo is set for cd input
stereo volume set to 11
-----Pushing Macro Off-----
living room light is off
kitchen light is off
living room celling fan is off
living room stereo is off


------------------------------


命令模式还有更多用途,比如队列请求,线程从队列中一个个的删除命令对象,然后调用命令对象的execute()。
工作队列类和进行计算的类是解耦的。
还有日志请求,Command接口多了Store()和load()方法,可以用来存储恢复!


----------------to conclude
我认为命令模式好处在于降低耦合,容易实现组合命令。
但是他每个命令都得是一个类,万一我好多命令。。。
正好这个学期软工有个大作业,是写进销存系统,进货销售什么的命令一大堆,可以使用这个模式,结构可以清晰点,还更符合OO思想。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值