深入浅出设计模式-006:命令模式(Command Pattern)
一:命令模式可以将“动作的请求者”从“动作的执行者”对象中解耦。 创建命令对象 利用setCommand将命令对象存储在调用者中 利用execute要求调用者执行命令
二:命令模式:将“请求”封装成对象,以便使用不同的请求或者队列或者日志来参数化其他对象。 也支持可撤销操作。
public class Light{ public String location; public Light(String location){ this.location = location; } public void On(){ Console.WriteLine(location + "/t Light On"); } public void Off(){ Console.WriteLine(location + "/t Light Off"); } }
public interface Command{ //执行命令 void execute(); } public class LightOnCommand : Command{ Light light; public LightOnCommand(Light light){ this.light = light; } public void execute(){ light.On(); } } public class LightOffCommand : Command{ Light light; public LightOffCommand(Light light){ this.light = light; } public void execute(){ light.Off(); } } public class SimpleRemoteControl{ Command slot; public SimpleRemoteControl() { } //接受命令 public void setCommand(Command command){ slot = command; } public void buttonWasPressed(){ slot.execute(); } } class Program//此乃客户 { static void Main(string[] args) { //调用者,用来发出请求 SimpleRemoteControl remote = new SimpleRemoteControl(); //创建对象,此对象即请求的接受者 Light light = new Light("1"); //创建命令, LightOnCommand lightOn = new LightOnCommand(light);
//将命令传给调用者,即(服务员下单) remote.setCommand(lightOn); remote.buttonWasPressed(); } }
三:命令模式将发出请求的对象和执行请求的对象解耦 在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接受者的一个或一组动作 调用者通过调用命令对象的EXECUTE发出请求,这会使得接受者的动作被调用 调用者可以接受命令当做参数,甚至在运行时动态地进行 命令可以支持撤销,撤销是实现一个UNDO方法来回到EXECUTE被执行前的状态 宏命令是命令的一种简单延伸,允许调用多个命令。宏方法也可以支持撤销。 命令可以用来实现日志和事物系统 public interface Command{ //执行命令 void execute(); void undo(); } public class NoCommand : Command{ public void execute() { return ; } public void undo() { return; } } public class MacroCommand : Command{ Command[] commands; public MacroCommand(Command[] commands){ this.commands = commands; } public void execute(){ for(int index=0; index<commands.Length; index++){ commands[index].execute(); } } public void undo(){ for (int index = 0; index < commands.Length; index++){ commands[index].undo(); } } } public class LightOnCommand : Command{ Light light; public LightOnCommand(Light light){ this.light = light; } public void execute(){ light.On(); } public void undo(){ light.Off(); } } public class LightOffCommand : Command{ Light light; public LightOffCommand(Light light){ this.light = light; } public void execute(){ light.Off(); } public void undo(){ light.On(); } } public class RemoteControl{ Command[] onCommands; Command[] offCommands; Command undoCommand;
public RemoteControl(){ onCommands = new Command[7]; offCommands = new Command[7];
//可以避免在每次调onButtonWasPushed时检测命令是否为空 Command noCommand = new NoCommand(); for (int index = 0; index < 7; index++){ onCommands[index] = noCommand; offCommands[index] = 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(){ StringBuilder sb = new StringBuilder(); sb.Append("/n------ Remote Control -------/n"); for (int i = 0; i < onCommands.Length; i++){ sb.Append("[slot " + i + "] " + onCommands[i].GetType().Name + " " + offCommands[i].GetType().Name + "/n"); } return sb.ToString(); } }
class Program { static void Main(string[] args) { //管理一组命令对象,每个按钮都有一个命令对象。 //每次按下按钮,就调用相应的**ButtonWasPushed方法,间接调用EXECUTE方法 RemoteControl remoteControl = new RemoteControl();
Light klight = new Light("1"); //利用Command接口,每个动作都被实现成一个简单得的命令对象。 //命令对象持有对一个厂商类的实例的引用,并实现EXECUTE方法 //这个方法会调用厂商类实例的一个或多个方法,完成特定的行为。 LightOnCommand lighton = new LightOnCommand(klight); LightOffCommand lightoff = new LightOffCommand(klight); //1号卡槽,控制电灯开关 remoteControl.setCommand(1, lighton, lightoff); remoteControl.onButtonWasPushed(1); remoteControl.offButtonWasPushed(1); remoteControl.undoButtonWasPushed();
Command[] partyOn = { lighton}; Command[] partyOff = { lightoff };
MacroCommand partyOnCmd = new MacroCommand(partyOn); MacroCommand partyOffCmd = new MacroCommand(partyOff);
//0号卡槽,控制所有设备的开关 remoteControl.setCommand(0, partyOnCmd, partyOffCmd); remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); } }