命令模式
定义
命令模式(Command Pattern)是一种行为设计模式,它将请求封装为独立的对象,从而允许用户参数化其他对象,并支持请求的排队、记录、撤销/重做等操作。该模式通过解耦请求的发送者和接收者,提高了系统的灵活性和可扩展性。
核心思想
- 将请求封装成对象:将每个操作(如“打开文件”“保存数据”)抽象为命令对象,包含执行操作所需的所有信息。
- 解耦调用者与接收者:调用者(如按钮、菜单)无需知道具体操作如何执行,只需触发命令对象;接收者(如文档、设备)负责实际执行操作。
模式结构
命令模式包含以下角色:
-
命令接口(Command)
定义执行操作的抽象方法(如execute()),通常包含撤销方法(如undo())。 -
具体命令(Concrete Command)
- 实现命令接口,关联一个接收者(Receiver)。
- 在
execute()中调用接收者的具体方法(如receiver.action())。
-
接收者(Receiver)
真正执行操作的对象(如“灯”执行“打开”或“关闭”)。 -
调用者(Invoker)
触发命令的对象(如按钮、遥控器),持有命令对象并调用其execute()。 -
客户端(Client)
创建具体命令对象,并设置其接收者和调用者。
工作流程
- 客户端创建命令对象,并关联接收者。
- 调用者持有命令对象,并在适当时机(如按钮点击)调用
execute()。 - 具体命令调用接收者的方法,完成实际操作。
- (可选)命令记录状态以支持撤销/重做。
代码示例
以“遥控器控制灯”为例:
using System;
// 1. 命令接口(定义执行和撤销操作)
public interface ICommand
{
void Execute();
void Undo();
}
// 2. 接收者:电灯(实际执行操作的对象)
public class Light
{
public void TurnOn() => Console.WriteLine( "电灯已打开" );
public void TurnOff() => Console.WriteLine( "电灯已关闭" );
}
// 3. 具体命令:开灯命令
public class TurnOnCommand : ICommand
{
private Light _light;
public TurnOnCommand(Light light)
{
_light = light;
}
public void Execute() => _light.TurnOn();
public void Undo() => _light.TurnOff();
}
// 4. 具体命令:关灯命令
public class TurnOffCommand : ICommand
{
private Light _light;
public TurnOffCommand(Light light)
{
_light = light;
}
public void Execute() => _light.TurnOff();
public void Undo() => _light.TurnOn();
}
// 5. 调用者:遥控器(触发命令的对象)
public class RemoteControl
{
private ICommand _command;
// 设置命令
public void SetCommand(ICommand command)
{
_command = command;
}
// 执行命令
public void PressButton()
{
_command.Execute();
}
// 撤销命令
public void PressUndo()
{
_command.Undo();
}
}
// 6. 客户端代码
class Program
{
static void Main()
{
// 创建接收者(电灯)
Light light = new Light();
// 创建具体命令并关联接收者
ICommand turnOn = new TurnOnCommand(light);
ICommand turnOff = new TurnOffCommand(light);
// 创建调用者(遥控器)
RemoteControl remote = new RemoteControl();
// 执行开灯命令
remote.SetCommand(turnOn);
remote.PressButton(); // 输出:电灯已打开
remote.PressUndo(); // 输出:电灯已关闭
// 执行关灯命令
remote.SetCommand(turnOff);
remote.PressButton(); // 输出:电灯已关闭
remote.PressUndo(); // 输出:电灯已打开
}
}
代码说明
-
命令接口
ICommand
定义Execute()和Undo()方法,所有具体命令必须实现这两个操作。 -
接收者
Light
实际执行操作的对象,提供TurnOn()和TurnOff()方法。 -
具体命令
TurnOnCommand/TurnOffCommand- 关联接收者
Light,并在Execute()中调用其方法。 Undo()实现反向操作(如开灯的撤销是关灯)。
- 关联接收者
-
调用者
RemoteControl- 持有命令对象,通过
PressButton()触发命令执行。 - 通过
PressUndo()触发撤销操作。
- 持有命令对象,通过
-
客户端
Program- 组合接收者、命令和调用者。
- 演示命令的链式调用(执行与撤销)。
扩展场景:宏命令(批量操作)
// 定义宏命令(组合多个命令)
public class MacroCommand : ICommand
{
List _commands = new List();
public void AddCommand(ICommand command)
{
_commands.Add(command);
}
public void Execute()
{
foreach ( var cmd in _commands)
{
cmd.Execute();
}
}
public void Undo()
{
// 反向撤销所有命令
foreach ( var cmd in _commands.AsEnumerable().Reverse())
{
cmd.Undo();
}
}
}
// 客户端使用宏命令
static void Main()
{
Light light = new Light();
ICommand turnOn = new TurnOnCommand(light);
ICommand turnOff = new TurnOffCommand(light);
// 创建宏命令(开灯 -> 关灯 -> 开灯)
MacroCommand macro = new MacroCommand();
macro.AddCommand(turnOn);
macro.AddCommand(turnOff);
macro.AddCommand(turnOn);
RemoteControl remote = new RemoteControl();
remote.SetCommand(macro);
Console.WriteLine( "执行宏命令:" );
remote.PressButton();
// 输出:
// 电灯已打开
// 电灯已关闭
// 电灯已打开
Console.WriteLine( "撤销宏命令:" );
remote.PressUndo();
// 输出:
// 电灯已关闭
// 电灯已打开
// 电灯已关闭
}
应用场景总结
- GUI 按钮/菜单:将点击事件绑定到命令对象。
- 事务管理:记录操作历史以实现撤销/重做。
- 任务队列:将命令存入队列异步执行。
- 批处理操作:通过宏命令组合多个操作。
命令模式在 C# 中广泛应用于 WPF 的 ICommand 接口(如 RelayCommand)、ASP.NET Core 中间件等场景,是解耦请求与处理的经典设计模式。

浙公网安备 33010602011771号