命令模式(Command Pattern)

简介

在面向对象程式设计的范畴中,命令模式是一种设计模式,它尝试以物件来代表实际行动。命令物件可以把行动(action) 及其参数封装起来,于是这些行动可以被:

  • 重复多次
  • 取消(如果该物件有实作的话)
  • 取消后又再重做

这些都是现代大型应用程序所必须的功能,即“复原”及“重复”。除此之外,可以用命令模式来实作的功能例子还有:

  • 交易行为
  • 进度列
  • 精灵
  • 使用者界面按钮及功能表项目
  • 执行绪 pool
  • 宏收录

命令模式 - 图1

JavaScript

  1. /* The Invoker function */
  2. var Switch = function(){
  3. var _commands = [];
  4. this.storeAndExecute = function(command){
  5. _commands.push(command);
  6. command.execute();
  7. }
  8. }
  9. /* The Receiver function */
  10. var Light = function(){
  11. this.turnOn = function(){ console.log ('turn on')};
  12. this.turnOff = function(){ console.log ('turn off') };
  13. }
  14. /* The Command for turning on the light - ConcreteCommand #1 */
  15. var FlipUpCommand = function(light){
  16. this.execute = light.turnOn;
  17. }
  18. /* The Command for turning off the light - ConcreteCommand #2 */
  19. var FlipDownCommand = function(light){
  20. this.execute = light.turnOff;
  21. }
  22. var light = new Light();
  23. var switchUp = new FlipUpCommand(light);
  24. var switchDown = new FlipDownCommand(light);
  25. var s = new Switch();
  26. s.storeAndExecute(switchUp);
  27. s.storeAndExecute(switchDown);

Java

  1. import java.util.List;
  2. import java.util.ArrayList;
  3. /* The Command interface */
  4. public interface Command {
  5. void execute();
  6. }
  7. /* The Invoker class */
  8. public class Switch {
  9. private List<Command> history = new ArrayList<Command>();
  10. public Switch() {
  11. }
  12. public void storeAndExecute(Command cmd) {
  13. this.history.add(cmd); // optional
  14. cmd.execute();
  15. }
  16. }
  17. /* The Receiver class */
  18. public class Light {
  19. public Light() {
  20. }
  21. public void turnOn() {
  22. System.out.println("The light is on");
  23. }
  24. public void turnOff() {
  25. System.out.println("The light is off");
  26. }
  27. }
  28. /* The Command for turning on the light - ConcreteCommand #1 */
  29. public class FlipUpCommand implements Command {
  30. private Light theLight;
  31. public FlipUpCommand(Light light) {
  32. this.theLight = light;
  33. }
  34. public void execute(){
  35. theLight.turnOn();
  36. }
  37. }
  38. /* The Command for turning off the light - ConcreteCommand #2 */
  39. public class FlipDownCommand implements Command {
  40. private Light theLight;
  41. public FlipDownCommand(Light light) {
  42. this.theLight = light;
  43. }
  44. public void execute() {
  45. theLight.turnOff();
  46. }
  47. }
  48. /* The test class or client */
  49. public class PressSwitch {
  50. public static void main(String[] args){
  51. Light lamp = new Light();
  52. Command switchUp = new FlipUpCommand(lamp);
  53. Command switchDown = new FlipDownCommand(lamp);
  54. Switch mySwitch = new Switch();
  55. try {
  56. if ("ON".equalsIgnoreCase(args[0])) {
  57. mySwitch.storeAndExecute(switchUp);
  58. }
  59. else if ("OFF".equalsIgnoreCase(args[0])) {
  60. mySwitch.storeAndExecute(switchDown);
  61. }
  62. else {
  63. System.out.println("Argument \"ON\" or \"OFF\" is required.");
  64. }
  65. } catch (Exception e) {
  66. System.out.println("Arguments required.");
  67. }
  68. }
  69. }

实例

模拟烧烤

紧耦合设计

  1. //烤肉串者
  2. public class Barbecuer
  3. {
  4. //烤羊肉
  5. public void BakeMutton()
  6. {
  7. Console.WriteMutton("烤羊肉串");
  8. }
  9. //烤鸡翅
  10. public void BakeChikenWing()
  11. {
  12. Console.WriteMutton("烤鸡翅");
  13. }
  14. }

客户端调用

  1. static void Main(string[] args)
  2. {
  3. Barbecuer boy = new Barbecuew();
  4. boy.BakeMutton();
  5. boy.BakeMutton();
  6. boy.BakeMutton();
  7. boy.BakeChickenWing();
  8. }

松耦合设计

抽象命令类

  1. //抽象命令
  2. public abstract class Command
  3. {
  4. protected Barbecuer receiver;
  5. public Command(Barbecuer receiver)
  6. {
  7. this.receiver = receiver;
  8. }
  9. //执行命令
  10. abstract public ExcuteCommand();
  11. }

具体命令类

  1. //烤羊肉命令
  2. class BakeMuttonCommand: Command
  3. {
  4. public BakeMuttonCommand(Barbecuer receiver)
  5. {
  6. :base(receiver)
  7. }
  8. public override void EccuteCommand()
  9. {
  10. receiver.BakeMutton();
  11. }
  12. }
  13. //烤鸡翅命令
  14. class BakeMuttonCommand: Command
  15. {
  16. public BakeMuttonCommand(Barbecuer receiver)
  17. {
  18. :base(receiver)
  19. }
  20. public override void EccuteCommand()
  21. {
  22. receiver.BakeChickenWing();
  23. }
  24. }

服务员类

  1. //服务员
  2. public class Waiter
  3. {
  4. private Command command;
  5. //设置订单
  6. public void setOrder(Command command)
  7. {
  8. this.command
  9. }
  10. //通知执行
  11. public void Notify()
  12. {
  13. command.ExcuteCommand();
  14. }
  15. }
  1. //烤肉串者
  2. public class Barbecuer
  3. {
  4. //烤羊肉
  5. public void BakeMutton()
  6. {
  7. Console.WriteMutton("烤羊肉串");
  8. }
  9. //烤鸡翅
  10. public void BakeChikenWing()
  11. {
  12. Console.WriteMutton("烤鸡翅");
  13. }
  14. }

客户端实现

  1. static void Main(string[] args)
  2. {
  3. //开店前的准备
  4. Barbecuer boy = new Barbecuer();
  5. Command BakeMuttonCommand1 = new BakeMuttonCommand(boy);
  6. Command BakeMuttonCommand2 = new BakeMuttonCommand(boy);
  7. Command BakeChickenWingCommand1 = new BakeMuttonCommand(boy);
  8. Waiter girl = new Waiter();
  9. //开门营业
  10. girl.SetOrder(BakeMuttonCommand1);
  11. girl.Notify();
  12. girl.SetOrder(BakeMuttonCommand2);
  13. girl.Notify();
  14. girl.SetOrder(BakeChickenWingCommand1);
  15. girl.Notify();
  16. COnsole.Read();
  17. }

松耦合后

  1. //服务员
  2. public class Waiter
  3. {
  4. private IList<Command> orders = new List<Command>();
  5. //设置订单
  6. public void SetOrder(Command command)
  7. {
  8. if (command.ToString() == "命令模式.BakeChikenWingCommand")
  9. {
  10. Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤。");
  11. }
  12. else
  13. {
  14. orders.Add(command);
  15. Console.WriteLine("增加订单:"+ command.ToString() + "时间" + DateTime.Now.ToString());
  16. }
  17. }
  18. //取消订单
  19. public void CancelOrder(Command command)
  20. {
  21. orders.Remove(command);
  22. Console.WriteLine("取消订单" + command.ToString() + "时间" + DateTime.Now.ToString());
  23. }
  24. //通知全部执行
  25. public void Notify()
  26. {
  27. foreach(Command cmd in orders)
  28. {
  29. cmd.ExcuteCommand();
  30. }
  31. }
  32. }

客户端代码实现

  1. static void Main(string[] args)
  2. {
  3. Barbecuer boy = new Barbecuer();
  4. Command BakeMuttonCommand1 = new BakeMuttonCommand(boy);
  5. Command BakeMuttonCommand2 = new BakeMuttonCommand(boy);
  6. Command BakeChickenWingCommand1 = new BakeMuttonCommand(boy);
  7. Waiter girl = new Waiter();
  8. girl.setOrder(bakeMuttonCommand1);
  9. girl.setOrder(bakeMuttonCommand1);
  10. girl.setOrder(BakeChickenWingCommand1);
  11. girl.Notify();
  12. Console.Read();
  13. }

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数话;对请求排队或者纪录请求日志,以及支持可撤销的操作。

命令模式的优点:

  • 容易地设计一个命令队列。
  • 在需求的情况下,比较容易地将命令记入日志。
  • 允许接受请求的一方决定是否要回绝请求。
  • 很容易对请求撤销或者重做。
  • 加入新的命令类不影响其它的类。
  • 把请求一个操作的对象与知道怎么执行一个操作的对象分割开。