设计模式(十九)命令模式

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

优点:

1、它能较容易地设计一个命令队列;

2、在需要的情况下,可以较容易地将命令记入日志;

3、允许接收请求的一方决定是否要否决请求;

4、可以容易地实现对请求的撤销和重做;

5、由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易;

6、命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。

敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际上不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。

 基本代码

 1 // Command 类,用来声明执行操作的接口
 2 abstract class Command
 3 {
 4   protected Receiver receiver;
 5 
 6   public Command(Receiver receiver)
 7   {
 8     this.receiver = receiver;
 9   }
10 
11   abstract public void Execute();
12 }
13 
14 // ConcreteCommand 类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现 Execute
15 class ConcreteCommand : Command
16 {
17   public ConcreteCommand(Receiver receiver) : base(receiver)
18   {
19   }
20   
21   public override void Execute()
22   {
23     receiver.Action();  
24   }
25 }
26 
27 // Invoker 类,要求该命令执行这个请求
28 class Invoker
29 {
30   private Command command;
31 
32   public void SetCommand(Command command)
33   {
34     this.command = command;
35   }
36 
37   public void ExecuteCommand()
38   {
39     command.Execute();
40   }
41 }
42 
43 // Receiver 类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者
44 class Receiver
45 {
46   public void Action()
47   {
48     Console.WriteLine("执行请求!");
49   }
50 }
51 
52 // 客户端
53 static void Main(string[] args)
54 {
55   Receiver r = new Receiver();
56   Command c = new ConcreteCommand();
57 
58   Invoker i = new Invoker();
59   i.SetCommand(c);
60   i.ExecuteCommand();
61 
62   Console.Read();
63 }

 【例】吃烧烤

基本代码

  1 // 烤肉串者
  2 public clas Barbecuer
  3 {
  4   // 烤羊肉
  5   public void BakeMutton()
  6   {
  7     Console.WriteLine("烤羊肉串");
  8   }
  9   // 烤鸡翅
 10   public void BakeChickenWing()
 11   {
 12     Console.WriteLine("烤鸡翅");
 13   }
 14 }
 15 
 16 // 抽象命令类,只需要确定 “烤肉串者” 是谁
 17 public abstract class Command
 18 {
 19   protected Barbecuer receiver;
 20 
 21   public Command(Barbecuer receiver)
 22   {
 23     this.receiver = receiver;
 24   }
 25   // 执行命令
 26   abstract public void ExecuteCommand();
 27 }
 28 
 29 // 具体命令类,执行命令时,执行具体的行为
 30 // 烤羊肉串命令
 31 class BakeMuttonCommand : Command
 32 {
 33   public BakeMuttonCommand(Barbecuer receiver) : base(receiver)
 34   {
 35   }
 36   
 37   public override void ExecuteCommand()
 38   {
 39     receiver.BakeMutton();  
 40   }
 41 }
 42 
 43 // 烤鸡翅命令
 44 class BakeChickenWingCommand : Command
 45 {
 46   public BakeChickenWingCommand(Barbecuer receiver) : base(receiver)
 47   {
 48   }
 49   
 50   public override void ExecuteCommand()
 51   {
 52     receiver.BakeChickenWing();  
 53   }
 54 }
 55 
 56 // 服务员类,不用管用户想要什么烤肉,反之都是 “命令”,只管记录订单,然后通知 “烤肉串者 ” 执行即可
 57 public class Waiter
 58 {
 59   // 增加存放具体命令的容器
 60   private IList<Command>orders = new List<Command>();
 61 
 62   // 设置订单
 63   public void SetOrder(Command command)
 64   {
 65     if(command.ToString() == "命令模式.BakeChickenWingCommand")
 66     {
 67       Console.WriteLine("服务员:鸡翅没了。");
 68     }else
 69     {
 70       orders.Add(command);
 71       // 记录日志
 72       Console.WriteLine("增加订单:" + command.ToString() + "时间:" + DateTime.Now.ToString());
 73     }
 74   }
 75  
 76   // 取消订单
 77   public void CancelOrder(Command command)
 78   {
 79       orders.Remove(command);
 80       // 记录日志
 81       Console.WriteLine("取消订单:" + command.ToString() + "时间:" + DateTime.Now.ToString());
 82   }
 83 
 84   // 通知执行(通知厨房制作)
 85   public void Notify()
 86   {
 87     foreach(Command cmd in orders)
 88     {
 89       cmd.ExecuteCommand();
 90     }
 91   }
 92 }
 93 
 94 // 客户端
 95 static void Main(string[] args)
 96 {
 97   // 开店前的准备(烤肉厨师、服务员、烤肉菜单)
 98   Barbecuer boy = new Barbecuer();
 99   Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
100   Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
101   Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
102   Waiter girl = new Waiter();
103 
104   // 开门营业(顾客点菜)
105   girl.SetOrder(bakeMuttonCommand1);
106   girl.SetOrder(bakeMuttonCommand2);
107   girl.SetOrder(bakeChickenWingCommand1);
108 
109   // 通知厨房(订单下好后,一次通知)
110   girl.Notify();
111 
112   Console.Read();
113 }

 

posted @ 2015-06-20 22:56  壬子木  阅读(106)  评论(0)    收藏  举报