设计模式之命令模式
设计模式之命令模式
命令模式可将”动作的请求者”从”动作的执行者”对象中解耦。
在设计中,采用”命令对象”,利用命令对象,把请求封装成一个特定的对象,如果每个按钮都存储一个命令对象,那么当按钮被按下的时候,就可以请命令对象做相关工作了。
第一个命令对象
实现命令接口
/// <summary>
/// 实现命令接口:让所有命令对象实现相同的包含一个方法的接口
/// </summary>
public interface Command
{
void execute();
}
实现一个打开电灯的命令
public class LightOnCommand : Command
{
private Light light;
public LightOnCommand(Light light)//构造方法中传入一个对象,当execute被调用的时候,就由这个对象作为接收者,接受请求。
{
this.light = light;
}
public void execute()//调用接收对象
{
light.@on();
}
}
使用命令对象
public class SimpleRemoteControl
{
private Command slot;//插槽持有命令,这个命令控制着一个装置
public SimpleRemoteControl()
{
}
public void setCommand(Command command)//用来设置插槽控制的命令
{
slot = command;
}
public void buttonWasPressed()//调用这个方法,使得当前命令衔接插槽被调用
{
slot.execute();
}
}
简单测试
static void Main(string[] args)
{
SimpleRemoteControl remote=new SimpleRemoteControl();//发出请求
Light light=new Light();//请求的接收者
LightOnCommand lightOn=new LightOnCommand(light);//创建一个命令,将接收者传给它
remote.setCommand(lightOn);//把命令传给调用者
remote.buttonWasPressed();//调用
Console.ReadKey();
}
定义命令模式
命令模式:将请求封装成对象,以便使用不同请求、队列、或者日志来参数化其他对象。命令模式也支持可撤销操作。
一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。命令对象将动作和接收者包进对象中,这个对象只暴漏出一个execute()方法,当此方法被调用的时候,接收者就会进行这些动作。
类图
client:这个客户负责创建一个ConcreteCommand,并设置其接收者。
Receiver:接收者知道如何进行必要的工作,实现这个请求。任何类都可以当接收者。
ConcreteCommand:这个ConcreteCommand定义了动作和接收者之间的绑定关系。
Invoker:这个调用者持有一个命令对象,并在某个时间点调用命令对象的execute方法,将请求实行。
Command:Command为所有命令声明了一个接口。调用命令对象的execute方法,就可以让接收者进行相关的动作。
使用反转命令
使用命令模式,我们还可以使用反转命令,撤销之前操作。
新增undo()
在命令接口中,新增undo()用于反转之前操作命令
public interface Command
{
void execute();
void undo();
}
执行
public class LightOnCommand : Command
{
private Light light;
public LightOnCommand(Light light)//构造方法中传入一个对象,当execute被调用的时候,就由这个对象作为接收者,接受请求。
{
this.light = light;
}
public void execute()//调用接收对象
{
light.@on();
}
public void undo()
{
light.off();
}
}
队列请求
命令可以将运算块打包,然后将它传来传去,就像是一般的对象一样。即使在命令对象被创建许久以后,运算依然可以被调用。这样就可以将它传入队列中使用。
队列对象不在乎到底做些什么,它们只知道取出命令对象,然后调用其execute()方法。
日志请求
某些应用需要我们将所有的动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态。
做法:当我们执行命令的时候,将历史记录存储在磁盘中,一旦系统死机,我们就可以将命令对象重新加载,并成批地依次调用这些对象的execute()方法。
通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,从检查点开始应用这些操作。