设计模式篇——初探命令模式
命令模式介绍
1、命令模式介绍:命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
PS:个人理解的命令模式就是将“请求”(方法)封装起来,这个请求中,存在一个或者多个接收者,然后把这个对象传递给一个Invoker(调用者)对象,并向外暴露出一个execute()方法,在特定的时刻调用这个execute方法,进而执行封装的请求方法。 这样做的优点就是外界不需要知道Receiver对象进行了哪些操作,我(外界)仅仅调用了execute方法而已;这样就实现了调用对象和调用的请求者之间的解耦。
2、命令模式类图
先大致看看,脑袋里面有个大体印象~~~emmmmmmmm
3、命令模式实例
现在我们将要实现一个遥控器,用来控制电灯开关,车库门的上下、开关灯等操作。
/// <summary> /// 定义请求对象接口,对外暴露方法Execute /// </summary> public interface ICommand { void Execute(); }
/// <summary> /// 定义一个电灯类,存在打开、关闭方法 /// </summary> public class Light { public void On() { Console.WriteLine("灯打开了"); } public void Off() { Console.WriteLine("灯关闭了"); } } /// <summary> /// 电灯打开指令,继承ICommand接口 /// </summary> public class LightOnCommand : ICommand { public Light _light; /// <summary> /// 构造函数传入电灯参数 /// </summary> /// <param name="light"></param> public LightOnCommand(Light light) { _light = light; } /// <summary> /// Execute方法将执行电灯的打开操作 /// </summary> public void Execute() { _light.On(); } } /// <summary> /// 同理,来一个电灯关闭的指令 /// </summary> public class LightOffCommand:ICommand { public Light _light; public LightOffCommand(Light light) { _light = light; } public void Execute() { _light.Off(); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// 同理,定义一个车库对象 /// </summary> public class GarageDoor { public void Up() { Console.WriteLine("车库门往上拉"); } public void Down() { Console.WriteLine("车库门往下降"); } public void Stop() { Console.WriteLine("车库门停止"); } public void lightOn() { Console.WriteLine("车库灯打开"); } public void lightOff() { Console.WriteLine("车库灯关闭"); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class GarageDoorOpenCommand : ICommand { GarageDoor _garageDoor; public GarageDoorOpenCommand(GarageDoor garageDoor) { _garageDoor = garageDoor; } public void Execute() { _garageDoor.Up(); _garageDoor.lightOn(); } } public class GarageDoorCloseCommand : ICommand { GarageDoor _garageDoor; public GarageDoorCloseCommand(GarageDoor garageDoor) { _garageDoor = garageDoor; } public void Execute() { _garageDoor.Down(); _garageDoor.lightOff(); } }
接下来让我们来定义一个遥控器:
public class NoCommand : ICommand { public void Execute() { Console.WriteLine("这个操作是个空操作"); } } /// <summary> /// 定义遥控器 /// </summary> public class RemoteControl { ICommand[] _icommandOnList; //一个ICommand 接口数组。 存放打开指令,理解为遥控器插槽 ICommand[] _icommandOffList; //另一个ICommand 接口数组,存放关闭指令。理解为遥控器插槽 public RemoteControl() { ICommand noCommand = new NoCommand(); _icommandOnList = new ICommand[2] { noCommand, noCommand }; //默认将控制另放入"插槽" _icommandOffList = new ICommand[2] { noCommand, noCommand }; } public void setCommand(int slot,ICommand onCommand,ICommand offCommand) //将具体设备指令方法对应位置的插槽 { _icommandOnList[slot] = onCommand; _icommandOffList[slot] = offCommand; } public void onButtonWasPushed(int slot) //按下指定位置的按钮,执行指定打开命令 { _icommandOnList[slot].Execute(); } public void offButtonWasPushed(int slot) //按下指定位置的按钮,执行指定打开命令 { _icommandOffList[slot].Execute(); } }
从开始我们就说,命令模式支持撤销操作,那现在让我们来加上撤销操作。
修改ICommand接口、
修改电灯和车库门的指令
同理,电灯的关闭指令以及车库门相关指令
接下来,修改遥控器类,添加一个“撤销插槽”
好,这样我们就完成了,让我们来测试一下
现在我们需要为遥控器添加一个宏命令。按下打开按钮的时候既可以开灯 又可以 拉起车库的门,同理,关闭按钮也可以执行所有的“关闭动作”
首先,然我们来定义一个“宏命令”类,这个类用来执行一组命令或者撤销一组命令~
public class MacroCommand:ICommand //创建一个宏命令 { ICommand[] _Commands; //用来存储一组命令 public MacroCommand(ICommand[] Commands) { _Commands = Commands; } public void Execute() //执行一组开的命令 { foreach(var commnad in _Commands) { commnad.Execute(); } } public void Undo() //执行一组撤销的命令 { foreach (var commnad in _Commands) { commnad.Undo(); } } }
这时候我们需要把电灯,车库的相关命令,放入宏命令中;再把宏命令放入遥控器的插槽“0”中去
NewCommand.RemoteControl remoteControl = new NewCommand.RemoteControl(); //遥控器 NewCommand.Light roomlight = new NewCommand.Light(); //电灯以及它的指令 NewCommand.LightOnCommand roomLightOnCommand = new NewCommand.LightOnCommand(roomlight); NewCommand.LightOffCommand roomLightOffCommand = new NewCommand.LightOffCommand(roomlight); GarageDoor garageDoor = new GarageDoor(); //车库门以及指令 GarageDoorOpenCommand garageOpenCommand = new GarageDoorOpenCommand(garageDoor); GarageDoorCloseCommand garageCloseCommand = new GarageDoorCloseCommand(garageDoor); //把一组打开的命令放入放入宏命令 MacroCommand onMacroCommand = new MacroCommand(new NewCommand.ICommand[] { roomLightOnCommand, garageOpenCommand }); //把一组关闭的命令放入放入宏命令 MacroCommand offMacroCommand = new MacroCommand(new NewCommand.ICommand[] { roomLightOffCommand, garageCloseCommand }); remoteControl.setCommand(0, onMacroCommand, offMacroCommand); //宏命令放入遥控器插槽 Console.WriteLine("打开宏命令"); remoteControl.onButtonWasPushed(0); Console.WriteLine("关闭宏命令"); remoteControl.offButtonWasPushed(0); Console.WriteLine("撤销宏命令"); remoteControl.undoButtonWasPushed();
让我们来测试下 =》
最后来总结下命令模式:
1、命令模式允许我们将动作封装成命令对象,这样我就可以随意存储,传递,调用它们。
2、命令模式将请求者和请求对象的执行者解耦,两者通过命令对象来进行沟通。
3、调用者(接收者)通过调用命令对象的execute()方法(本例中)发出请求,请求对象的执行者执行相应的方法。
4、调用者可以接受命令当做参数。
5、命令可以支持撤销,方法是实现一个undo()方法(本例中),回到执行execute()执行前的状态
6、宏命令允许调用多个命令,宏命令的撤销也能撤销多个命令。
7、命令对象可以直接实现请求,不用将工作委托给接收者