设计模式6-命令模式

151 阅读2分钟

1.场景问题解决

1.1 场景描述

智能家居项目.
家里有电灯,音箱,电视等子设备,有各自的开关接口.
现需要一个:总的开关设备,将所有的家居都能控制起来.

1.2 OO设计

if,else判断,或者Case when处理.

1.3 需求变动

如果增加新或修改设备,就要修改总开关设备.

1.4 带来问题

要求总开关设备:扩展性好、维护性好.当前oo设计耦合性强.

2.用设计模式改进

2.1 分析

2.2 重新设计

06命令模式-1类图

3.设计模式总结

3.1 定义

命令模式: 将请求、命令、动作等封装成对象,这样可以让项目使用这些对象来参数化其他对象。使得命令的请求者和执行者解耦

3.2 分析思路

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

  • 实现类(LightOnCommand[灯开],LightOffCommand[灯关],StereoOnCommand[音响开],StereoOffCommand[印象关],StereoAddVolCommand[音箱声音加],StereoSubVolCommand[音箱声音减],NoCommand[空命令],MarcoCommand[宏命令])
public class LightOnCommand implements Command {
	private Light light;
	
	public LightOnCommand(Light light){
		this.light=light;
	}
	@Override
	public void execute() {
		light.On();
	}

	@Override
	public void undo() {
		light.Off();
	}
}



public class LightOffCommand implements Command {
	private Light light;
	public LightOffCommand(Light light){
		this.light=light;
	}

	@Override
	public void execute() {
		light.Off();
	}

	@Override
	public void undo() {
		light.On();
	}
}


public class StereoOnCommand implements Command {
	private Stereo setreo;
	public StereoOnCommand(Stereo setreo) {
		this.setreo=setreo;
	}
	
	@Override
	public void execute() {
		setreo.On();
		setreo.SetCd();
		
	}
	@Override
	public void undo() {
		setreo.Off();
	}
}



public class StereoOffCommand implements Command {
	private Stereo setreo;
	public StereoOffCommand(Stereo setreo){
		this.setreo=setreo;
	}
	
	@Override
	public void execute() {
		setreo.Off();
	}

	@Override
	public void undo() {
		setreo.On();
		setreo.SetCd();
	}
}


public class StereoAddVolCommand implements Command {
	private Stereo setreo;
	public StereoAddVolCommand(Stereo setreo) {
		this.setreo=setreo;
	}
	
	@Override
	public void execute() {
		int vol=	setreo.GetVol();
		if(vol<11) {
			setreo.SetVol(++vol);
		}
	}

	@Override
	public void undo() {
		int vol=	setreo.GetVol();
		if(vol>0){
			setreo.SetVol(--vol);
		}
	}
}



public class StereoSubVolCommand implements Command {
	private Stereo setreo;
	public StereoSubVolCommand(Stereo setreo){
		this.setreo=setreo;
	}
	
	@Override
	public void execute() {
		int vol=	setreo.GetVol();
		if(vol>0){
			setreo.SetVol(--vol);
		}
	}

	@Override
	public void undo() {
		int vol= setreo.GetVol();
		if(vol<11){
			setreo.SetVol(++vol);
		}
	}
}

public class NoCommand implements Command {
	@Override
	public void execute() {
	}

	@Override
	public void undo() {
	}
}

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

	@Override
	public void execute() {
		for (int i = 0, len = commands.length; i < len; i++) {
			commands[i].execute();
		}
	}

	@Override
	public void undo() {
		for (int i = commands.length - 1; i >= 0; i--) {
			commands[i].undo();
		}
	}
}


--- CommandModeControl(插槽[命令集合器])

public class CommandModeControl implements Control{
	private Command[] onCommands;
	private Command[] offCommands;
	private Stack<Command> stack=new Stack<Command>();
	public CommandModeControl(){
		onCommands=new Command[5];
		offCommands=new Command[5];

		Command noCommand=new NoCommand();

		for(int i=0,len=onCommands.length;i<len;i++)
		{
		 onCommands[i]=noCommand;
		 offCommands[i]=noCommand;
		}
	}
	
	public void setCommand(int slot,Command onCommand,Command offCommand){
		onCommands[slot]=onCommand;
		offCommands[slot]=offCommand;
		
	}

	@Override
	public void onButton(int slot) {
		onCommands[slot].execute();
		stack.push(onCommands[slot]);
	}

	@Override
	public void offButton(int slot) {
		offCommands[slot].execute();
		stack.push(offCommands[slot]);
	}

	@Override
	public void undoButton() {
		stack.pop().undo();
	}
}

-- 测试类


public class CommandControlTest {

	public static void main(String[] args) {
		CommandModeControl control = new CommandModeControl();
		MarcoCommand onmarco,offmarco;
		Light bedroomlight = new Light("BedRoom");
		Light kitchlight = new Light("Kitch");
		Stereo stereo = new Stereo();
		
		LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
		LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
		LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
		LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);

		 Command[] oncommands={bedroomlighton,kitchlighton};
		 Command[] offcommands={bedroomlightoff,kitchlightoff};
			
		onmarco=new MarcoCommand(oncommands);
		offmarco=new MarcoCommand(offcommands);
		
		StereoOnCommand stereoOn = new StereoOnCommand(stereo);
		StereoOffCommand stereoOff = new StereoOffCommand(stereo);
		StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
		StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);

		control.setCommand(0, bedroomlighton, bedroomlightoff);
		control.setCommand(1, kitchlighton, kitchlightoff);
		control.setCommand(2, stereoOn, stereoOff);
		control.setCommand(3, stereoaddvol, stereosubvol);
		control.setCommand(4, onmarco, offmarco);

		control.onButton(0);
		control.undoButton();
		//control.offButton(0);
		control.onButton(1);
		control.offButton(1);
		control.onButton(2);
		control.onButton(3);
				
		control.offButton(3);
		control.undoButton();
		control.offButton(2);
		control.undoButton();
		control.onButton(4);
		control.offButton(4);
	}
}

3.3 总结归纳

转换思想,将命令定义为对象.而不是动作.虽然类、代码更多了,但是解耦了,扩展新也更强了,可以整个每个对象(灯具,音箱)来执行响应的动作。

4. 设计模式使用场景及注意

5.参考文章

内容总计于HeadFirst设计模式及相关视频