命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
首先先定义一个Command接口
interface Command
{
void Execute();
}
再定义几个Command的实现类
class Circle : Command
{
public void Execute()
{
Console.WriteLine("执行圆");
}
}
class Ring : Command
{
public void Execute()
{
Console.WriteLine("执行圆环");
}
}
定义一个封装类
class Invoke
{
private List<Command> commandList;
public Invoke()
{
commandList = new List<Command>();
}
public void AddCommand(Command command)
{
commandList.Add(command);
}
public void ExecuteCommand()
{
foreach(Command command in _commandList)
{
command.Execute();
}
}
}
调用
class Program
{
static void Main(string[] args)
{
Command circle = new Circle();
Command ring = new Ring();
Invoke invoke = new Invoke();
invoke.AddCommand(circle);
invoke.AddCommand(ring);
invoke.ExecuteCommand();
Console.Read();
}
}
结果
执行圆
执行圆环
类图
增加Undo/Redo操作
首先修改Command接口,增加一个Undo方法
interface Command
{
void Execute();
void Undo();
}
增加Comand接口实现类的Undo方法
class Circle : Command
{
public void Execute()
{
Console.WriteLine("执行圆");
}
public void Undo()
{
Console.WriteLine("撤销圆");
}
}
class Ring : Command
{
public void Execute()
{
Console.WriteLine("执行圆环");
}
public void Undo()
{
Console.WriteLine("撤销圆环");
}
}
修改封装类
class Invoke
{
private List<Command> undoList;
private List<Command> redoList;
// 可撤销的步数,-1是无限步
private int undoCount = -1;
public Invoke()
{
undoList = new List<Command>();
redoList = new List<Command>();
}
public void ExecuteCommand(Command command)
{
command.Execute();
undoList.Add(command);
// 保留最近undoCount次操作,删除最早操作
if (undoCount != -1 && undoList.Count > undoCount)
{
undoList.RemoveAt(0);
}
// 执行新操作后清空redoList,因为这些操作不能恢复了
redoList.Clear();
}
public void Undo()
{
if (undoList.Count <= 0)
{
return;
}
Command cmd = undoList[undoList.Count - 1];
cmd.Undo();
undoList.Remove(cmd);
redoList.Add(cmd);
}
public void Redo()
{
if (redoList.Count <= 0)
{
return;
}
Command cmd = redoList[redoList.Count - 1];
cmd.Execute();
redoList.Remove(cmd);
undoList.Add(cmd);
}
}
修改调用
class Program
{
static void Main(string[] args)
{
Command circle = new Circle();
Command ring = new Ring();
Invoke invoke = new Invoke();
invoke.ExecuteCommand(circle);
invoke.ExecuteCommand(ring);
invoke.Undo();
invoke.Redo();
//无效操作
invoke.Redo();
//撤销两次
invoke.Undo();
invoke.Undo();
//恢复两次
invoke.Redo();
invoke.Redo();
Console.Read();
}
}
结果
执行圆
执行圆环
撤销圆环
执行圆环
撤销圆环
撤销圆
执行圆
执行圆环
类图
优点与缺点
命令模式的优点:
- 命令模式使得新的命令很容易被加入到系统里。
- 可以设计一个命令队列来实现对请求的Undo和Redo操作。
- 可以较容易地将命令写入日志。
- 可以把命令对象聚合在一起,合成为合成命令。合成命令式合成模式的应用。
命令模式的缺点:
- 使用命令模式可能会导致系统有过多的具体命令类。这会使得命令模式在这样的系统里变得不实际。
本文主要借鉴了《Gof设计模式》