命令模式
概述
命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。
结构图
代码实现
命令
/// <summary> /// 抽象命令类 /// </summary> public abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } abstract public void Execute(); }
/// <summary> /// 具体命令实现 /// </summary> public class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.Action(); } }
请求者
/// <summary> /// 请求者/调用者 /// </summary> public class Invoker { private Command command; public void SetCommand(Command command) { this.command = command; } public void ExecuteCommand() { command.Execute(); } }
接收者
/// <summary> /// 抽象接收者/实现者 /// </summary> public abstract class Receiver { public abstract void Action(); }
/// <summary> /// 接收者A/实现者A /// </summary> public class ReceiverA: Receiver { public override void Action() { Console.WriteLine("A执行请求!"); } }
/// <summary> /// 接收者B/实现者B /// </summary> public class ReceiverB : Receiver { public override void Action() { Console.WriteLine("B执行请求!"); } }
客户端
class Program { static void Main(string[] args) { Receiver rA = new ReceiverA(); Command cA = new ConcreteCommand(rA); Receiver rB = new ReceiverB(); Command cB = new ConcreteCommand(rB); Invoker i = new Invoker(); i.SetCommand(cA); i.ExecuteCommand(); i.SetCommand(cB); i.ExecuteCommand(); Console.Read(); } }
运行结果
优势
降低了系统耦合度。扩展性良好,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,且满足“开闭原则”。
新的命令可以很容易添加到系统中去。
使用场景
异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等。
软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时。
当系统的某项操作具备命令语义,且命令实现不稳定(变化)时,可以通过命令模式解耦请求与实现。
请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
缺陷
使用命令模式可能会导致某些系统有过多的具体命令类。