C# 设计模式系列教程-命令模式
什么是命令模式
命令模式是一种行为设计模式,它能把请求或操作封装起来,以便在不同上下文中进行参数化、延迟执行或支持撤销操作。命令模式把命令的发送者和接收者解耦,并且把命令操作封装成对象,这些对象可以用队列进行管理。
在命令模式中,任何对象都可以扮演“命令”的角色,唯一的要求是具备两项能力:
- 执行这个请求的操作。
- 把请求的接收者传递到执行的操作中。
通常情况下,会为每一种命令都创建一个类,这个类包含了接收者以及需要执行的方法。
命令模式的实现
命令模式的实现包含如下角色:
- Command(抽象命令类):声明了一组用于执行操作的抽象方法,通常包含
Execute()
和Undo()
,其中Execute()
方法用于执行具体的命令操作,Undo()
方法用于撤销该操作。 - ConcreteCommand(具体命令类):继承了 Command,实现了抽象方法,可以定义自己的逻辑来处理请求,并且可以保持一些额外的状态变量。
- Invoker(调用者):会持有一个命令对象,并且在需要的时候,通过调用
Execute()
方法来触发命令。 - Receiver(接收者):这个对象会实现具体的业务逻辑,并且能够完成 Command 对象需要执行的任何操作。此外,它们为 Command 对象提供了执行操作所需的任何上下文信息。
设计模式示例说明
示例一
假设我们现在有一个遥控器,它有若干个按钮可以控制电器。
我们可以使用命令模式来实现这个功能。
- 创建
Command
接口:
public interface ICommand
{
void Execute();
void Undo();
}
其中 Execute
和 Undo
方法定义了我们需要的操作。
- 创建
Light
类作为接收者:
public class Light
{
public void On() { Console.WriteLine("Light is on"); }
public void Off() { Console.WriteLine("Light is off"); }
}
这个类表示了我们要控制的电器。
- 创建具体命令类
LightOnCommand
和LightOffCommand
:
public class LightOnCommand : ICommand
{
private readonly Light _light;
public LightOnCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.On();
}
public void Undo()
{
_light.Off();
}
}
public class LightOffCommand : ICommand
{
private readonly Light _light;
public LightOffCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.Off();
}
public void Undo()
{
_light.On();
}
}
- 创建
RemoteControl
类作为调用者:
public class RemoteControl
{
private readonly ICommand[] _onCommands;
private readonly ICommand[] _offCommands;
public RemoteControl()
{
_onCommands = new ICommand[7];
_offCommands = new ICommand[7];
// 初始化命令数组
for (var i = 0; i < 7; i++)
{
_onCommands[i] = new NoCommand();
_offCommands[i] = new NoCommand();
}
}
public void SetCommand(int slot, ICommand onCommand, ICommand offCommand)
{
_onCommands[slot] = onCommand;
_offCommands[slot] = offCommand;
}
public void OnButtonWasPushed(int slot)
{
_onCommands[slot].Execute();
}
public void OffButtonWasPushed(int slot)
{
_offCommands[slot].Execute();
}
}
这个类实例化一个 ICommand
数组,同时实现了 SetCommand
、OnButtonWasPushed
和 OffButtonWasPushed
方法。当执行某个命令时,会调用相应的 Execute
方法。
- 编写测试代码:
var remoteControl = new RemoteControl();
var light = new Light();
var lightOnCommand = new LightOnCommand(light);
var lightOffCommand = new LightOffCommand(light);
remoteControl.SetCommand(0, lightOnCommand, lightOffCommand);
remoteControl.OnButtonWasPushed(0); // Light is on
remoteControl.OffButtonWasPushed(0); // Light is off
通过测试代码的执行,我们可以实现控制电器打开和关闭的功能。
示例二
我们现在来实现一个简单的遥控器,它有两个按钮:一个按钮用来开门,另一个按钮用来关门。同时,我们需要实现撤销功能,可以撤销最后一个操作。
- 创建
Door
类作为接收者:
public class Door
{
private bool _isOpen;
public bool IsOpen() => _isOpen;
public void Open()
{
Console.WriteLine("Door is open");
_isOpen = true;
}
public void Close()
{
Console.WriteLine("Door is closed");
_isOpen = false;
}
}
这个类表示了我们要控制的门。
- 创建具体命令类
OpenDoorCommand
和CloseDoorCommand
:
public class OpenDoorCommand : ICommand
{
private readonly Door _door;
public OpenDoorCommand(Door door)
{
_door = door;
}
public void Execute()
{
_door.Open();
}
public void Undo()
{
_door.Close();
}
}
public class CloseDoorCommand : ICommand
{
private readonly Door _door;
public CloseDoorCommand(Door door)
{
_door = door;
}
public void Execute()
{
_door.Close();
}
public void Undo()
{
_door.Open();
}
}
- 创建
SimpleRemoteControl
类作为调用者:
public class SimpleRemoteControl
{
private ICommand _lastCommand;
public void SetCommand(ICommand command)
{
_lastCommand = command;
}
public void ButtonWasPressed()
{
_lastCommand.Execute();
}
public void UndoButtonWasPressed()
{
_lastCommand.Undo();
}
}
这个类实现了 SetCommand
、ButtonWasPressed
和 UndoButtonWasPressed
方法。同时,还用一个成员变量 _lastCommand
记录最后一次执行的命令。
- 编写测试代码:
var door = new Door();
var openCommand = new OpenDoorCommand(door);
var closeCommand = new CloseDoorCommand(door);
var remote = new SimpleRemoteControl();
remote.SetCommand(openCommand);
remote.ButtonWasPressed(); // Door is open
remote.UndoButtonWasPressed(); // Door is closed
remote.SetCommand(closeCommand);
remote.ButtonWasPressed(); // Door is closed
remote.UndoButtonWasPressed(); // Door is open
通过测试代码的执行,我们可以实现开门、关门以及撤销功能。
总结
命令模式能够把一个请求封装为一个对象,并且能够进行动态地参数化、队列化、简单的请求或撤销。通过使用这个模式,我们可以将发出命令的对象和执行命令的对象进行解耦。同时,命令模式还能够维护一组对象,这些对象能够随时添加、删除或替换。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 设计模式系列教程-命令模式 - Python技术站