索引
别名
意图
结构
参与者
适用性
效果
相关模式
实现
实现方式(一):直接注入 Receiver 对象,Command 决定调用哪个方法。
实现方式(二):注入 Receiver 的指定方法,Command 仅能调用该方法。
实现方式(三):参数化 Command 构造。
实现方式(四):使用泛型减少 Command 子类。
实现方式(五):使用弱引用代替对 Receiver 的强引用。
实现方式(六):使 Command 支持 Undo 和 Redo。
实现方式(七):使 MacroCommand 来管理 Command 序列。
别名
Action
Transaction
意图
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
结构
参与者
Command
声明 Execute 操作的接口。
ConcreteCommand
将一个接收者对象绑定于一个动作。
调用接收者相应的操作,以实现 Execute。
Client
创建一个具体 Command 对象并设定它的接收者。
Invoker
要求 Command 执行请求。
Receiver
知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
适用性
在以下情况下可以使用 Command 模式:
Command 模式是回调(callback)机制的一个面向对象的替代品。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。
在不同的时刻指定、排列和执行请求。Command 对象可以有一个与初始请求无关的生存期。
支持取消操作。需要定义 Unexecute 操作来取消 Execute 操作调用的效果。
支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。
用构建在原语操作上的高层操作构造一个系统。例如构建事务(Transaction)系统。
效果
Command 模式将调用操作的对象与知道如何实现该操作的对象解耦。
Command 是 first-class 对象。它们可像其他的对象一样被操纵和扩展。
可以将多个 Command 装配成一个复合 Command。
增加新的 Command 很容易,因为无需改变已有的类
相关模式
Composite 模式可被用来实现 MacroCommand。
Memento 模式可用来保持某个状态,Command 用这一状态来取消它的效果。
可以使用 Prototype 来拷贝 Command 对象。
实现
实现方式(一):直接注入 Receiver 对象,Command 决定调用哪个方法。
1 namespace CommandPattern.Implementation1 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 } 7 8 public class ConcreteCommand : Command 9 {10 private Receiver _receiver;11 12 public ConcreteCommand(Receiver receiver)13 {14 _receiver = receiver;15 }16 17 public override void Execute()18 {19 _receiver.Action();20 }21 }22 23 public class Receiver24 {25 public void Action()26 {27 // do something28 }29 }30 31 public class Invoker32 {33 private Command _cmd;34 35 public void StoreCommand(Command cmd)36 {37 _cmd = cmd;38 }39 40 public void Invoke()41 {42 if (_cmd != null)43 {44 _cmd.Execute();45 }46 }47 }48 49 public class Client50 {51 public void TestCase1()52 {53 Receiver receiver = new Receiver();54 Command cmd = new ConcreteCommand(receiver);55 56 Invoker invoker = new Invoker();57 invoker.StoreCommand(cmd);58 59 invoker.Invoke();60 }61 }62 }
实现方式(二):注入 Receiver 的指定方法,Command 仅能调用该方法。
1 namespace CommandPattern.Implementation2 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 } 7 8 public class ConcreteCommand : Command 9 {10 private Action _action;11 12 public ConcreteCommand(Action action)13 {14 _action = action;15 }16 17 public override void Execute()18 {19 _action.Invoke();20 }21 }22 23 public class Receiver24 {25 public void Action()26 {27 // do something28 }29 }30 31 public class Invoker32 {33 private Command _cmd;34 35 public void StoreCommand(Command cmd)36 {37 _cmd = cmd;38 }39 40 public void Invoke()41 {42 if (_cmd != null)43 {44 _cmd.Execute();45 }46 }47 }48 49 public class Client50 {51 public void TestCase2()52 {53 Receiver receiver = new Receiver();54 Command cmd = new ConcreteCommand(receiver.Action);55 56 Invoker invoker = new Invoker();57 invoker.StoreCommand(cmd);58 59 invoker.Invoke();60 }61 }62 }
实现方式(三):参数化 Command 构造。
1 namespace CommandPattern.Implementation3 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 } 7 8 public class ConcreteCommand : Command 9 {10 private Action<string> _action;11 private string _state;12 13 public ConcreteCommand(Action<string> action, string state)14 {15 _action = action;16 _state = state;17 }18 19 public override void Execute()20 {21 _action.Invoke(_state);22 }23 }24 25 public class Receiver26 {27 public void Action(string state)28 {29 // do something30 }31 }32 33 public class Invoker34 {35 private Command _cmd;36 37 public void StoreCommand(Command cmd)38 {39 _cmd = cmd;40 }41 42 public void Invoke()43 {44 if (_cmd != null)45 {46 _cmd.Execute();47 }48 }49 }50 51 public class Client52 {53 public void TestCase3()54 {55 Receiver receiver = new Receiver();56 Command cmd = new ConcreteCommand(receiver.Action, "Hello World");57 58 Invoker invoker = new Invoker();59 invoker.StoreCommand(cmd);60 61 invoker.Invoke();62 }63 }64 }
实现方式(四):使用泛型减少 Command 子类。
1 namespace CommandPattern.Implementation4 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 } 7 8 public class ConcreteCommand<T, S> : Command 9 {10 private Action<T, S> _action;11 private T _state1;12 private S _state2;13 14 public ConcreteCommand(Action<T, S> action, T state1, S state2)15 {16 _action = action;17 _state1 = state1;18 _state2 = state2;19 }20 21 public override void Execute()22 {23 _action.Invoke(_state1, _state2);24 }25 }26 27 public class Receiver28 {29 public void Action(string state1, int state2)30 {31 // do something32 }33 }34 35 public class Invoker36 {37 private Command _cmd;38 39 public void StoreCommand(Command cmd)40 {41 _cmd = cmd;42 }43 44 public void Invoke()45 {46 if (_cmd != null)47 {48 _cmd.Execute();49 }50 }51 }52 53 public class Client54 {55 public void TestCase4()56 {57 Receiver receiver = new Receiver();58 Command cmd = new ConcreteCommand<string, int>(59 receiver.Action, "Hello World", 250);60 61 Invoker invoker = new Invoker();62 invoker.StoreCommand(cmd);63 64 invoker.Invoke();65 }66 }67 }
实现方式(五):使用弱引用代替对 Receiver 的强引用。
1 namespace CommandPattern.Implementation5 2 { 3 public class WeakAction 4 { 5 public WeakAction(Action action) 6 { 7 Method = action.Method; 8 Reference = new WeakReference(action.Target); 9 }10 11 protected MethodInfo Method { get; private set; }12 protected WeakReference Reference { get; private set; }13 14 public bool IsAlive15 {16 get { return Reference.IsAlive; }17 }18 19 public object Target20 {21 get { return Reference.Target; }22 }23 24 public void Invoke()25 {26 if (Method != null && IsAlive)27 {28 Method.Invoke(Target, null);29 }30 }31 }32 33 public abstract class Command34 {35 public abstract void Execute();36 }37 38 public class ConcreteCommand : Command39 {40 private WeakAction _action;41 42 public ConcreteCommand(Action action)43 {44 _action = new WeakAction(action);45 }46 47 public override void Execute()48 {49 _action.Invoke();50 }51 }52 53 public class Receiver54 {55 public void Action()56 {57 // do something58 }59 }60 61 public class Invoker62 {63 private Command _cmd;64 65 public void StoreCommand(Command cmd)66 {67 _cmd = cmd;68 }69 70 public void Invoke()71 {72 if (_cmd != null)73 {74 _cmd.Execute();75 }76 }77 }78 79 public class Client80 {81 public void TestCase5()82 {83 Receiver receiver = new Receiver();84 Command cmd = new ConcreteCommand(receiver.Action);85 86 Invoker invoker = new Invoker();87 invoker.StoreCommand(cmd);88 89 invoker.Invoke();90 }91 }92 }
实现方式(六):使 Command 支持 Undo 和 Redo。
如果 Command 提供方法逆转操作,例如 Undo 操作,就可以取消执行的效果。为达到这个目的,ConcreteCommand 类可能需要存储额外的状态信息。
这个状态包括:
接收者对象,它真正执行处理该请求的各操作。
接收者上执行操作的参数。
如果处理请求的操作会改变接收者对象中的某些值,那么这些值也必须先存储起来。接收者还必须提供一些操作,以使该命令可将接收者恢复到它先前的状态。
1 namespace CommandPattern.Implementation6 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 public abstract void Unexecute(); 7 public abstract void Reexecute(); 8 } 9 10 public class ConcreteCommand : Command11 {12 private Receiver _receiver;13 private string _state;14 private string _lastState;15 16 public ConcreteCommand(Receiver receiver, string state)17 {18 _receiver = receiver;19 _state = state;20 }21 22 public override void Execute()23 {24 _lastState = _receiver.Name;25 _receiver.ChangeName(_state);26 }27 28 public override void Unexecute()29 {30 _receiver.ChangeName(_lastState);31 _lastState = string.Empty;32 }33 34 public override void Reexecute()35 {36 Unexecute();37 Execute();38 }39 }40 41 public class Receiver42 {43 public string Name { get; private set; }44 45 public void ChangeName(string name)46 {47 // do something48 Name = name;49 }50 }51 52 public class Invoker53 {54 private Command _cmd;55 56 public void StoreCommand(Command cmd)57 {58 _cmd = cmd;59 }60 61 public void Invoke()62 {63 if (_cmd != null)64 {65 _cmd.Execute();66 }67 }68 69 public void UndoInvoke()70 {71 if (_cmd != null)72 {73 _cmd.Unexecute();74 }75 }76 }77 78 public class Client79 {80 public void TestCase6()81 {82 Receiver receiver = new Receiver();83 Command cmd = new ConcreteCommand(receiver, "Hello World");84 85 Invoker invoker = new Invoker();86 invoker.StoreCommand(cmd);87 88 invoker.Invoke();89 invoker.UndoInvoke();90 }91 }92 }
实现方式(七):使 MacroCommand 来管理 Command 序列。
MacroCommand 需要提供增加和删除子 Command 的操作。
1 namespace CommandPattern.Implementation7 2 { 3 public abstract class Command 4 { 5 public abstract void Execute(); 6 } 7 8 public class MacroCommand : Command 9 { 10 private List<Command> _cmdList = new List<Command>(); 11 12 public MacroCommand() 13 { 14 } 15 16 public void Add(Command cmd) 17 { 18 _cmdList.Add(cmd); 19 } 20 21 public void Remove(Command cmd) 22 { 23 _cmdList.Remove(cmd); 24 } 25 26 public override void Execute() 27 { 28 foreach (var cmd in _cmdList) 29 { 30 cmd.Execute(); 31 } 32 } 33 } 34 35 public class ConcreteCommand1 : Command 36 { 37 private Receiver _receiver; 38 39 public ConcreteCommand1(Receiver receiver) 40 { 41 _receiver = receiver; 42 } 43 44 public override void Execute() 45 { 46 _receiver.Action1(); 47 } 48 } 49 50 public class ConcreteCommand2 : Command 51 { 52 private Receiver _receiver; 53 54 public ConcreteCommand2(Receiver receiver) 55 { 56 _receiver = receiver; 57 } 58 59 public override void Execute() 60 { 61 _receiver.Action2(); 62 } 63 } 64 65 public class Receiver 66 { 67 public void Action1() 68 { 69 // do something 70 } 71 72 public void Action2() 73 { 74 // do something 75 } 76 } 77 78 public class Invoker 79 { 80 private Command _cmd; 81 82 public void StoreCommand(Command cmd) 83 { 84 _cmd = cmd; 85 } 86 87 public void Invoke() 88 { 89 if (_cmd != null) 90 { 91 _cmd.Execute(); 92 } 93 } 94 } 95 96 public class Client 97 { 98 public void TestCase7() 99 {100 Receiver receiver = new Receiver();101 Command cmd1 = new ConcreteCommand1(receiver);102 Command cmd2 = new ConcreteCommand2(receiver);103 MacroCommand macro = new MacroCommand();104 macro.Add(cmd1);105 macro.Add(cmd2);106 107 Invoker invoker = new Invoker();108 invoker.StoreCommand(macro);109 110 invoker.Invoke();111 }112 }113 }
《设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。