• 编程模式之15---行为型----命令模式


    定义

    将一个请求封装成一个对象,让你可以用不同的请求对客户端进行参数化,对请求排队,纪录请求日志和支持可撤消操作.

    有三个具体成员,请求的发送者,请求的接收者,还有就是请求本身(或者是命令).对客户端进行参数化,也就是客户端可以把请求对象当成一个参数,直接注入到请求发送者内部,不用管请求接收者;对请求排队,如果一个请求发送者发送了一个请求,有多个接收者会处理这个请求的话,那么就需要对命令排队,命令对象和请求接收者是一一对应的;纪录请求日志,当发出一个请求时,由命令对象来保存一些信息,证明本对象被使用了,也可以说是本命令被处理了;支持可撤消操作,比如一个加法命令,命令对象纪录下加数,通过减去这个加数就实现了一次撤消,通过再加上这个加数就实现了一次恢复.

    结构组成

    从定义中,可以看出,一次完整的命令(请求)处理需要有三种类型成员参与.

    抽象命令类(Command):声明了执行请求的方法Execute,方法中调用请求接收者的处理方法.

    具体命令类(ConcreteCommand):实现方法Execute,每个具体命令类对应一个请求处理者.

    调用者(Invoke):发送命令者,维护一个命令对象的引用.调用命令类的Execute方法.

    接收者(Receiver):定义了用于处理请求的业务方法.最终的处理还是在业务方法中.

    示例

       

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 using System.Configuration;
     5 using System.Reflection;
     6 
     7 namespace 命令模式
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             Configuration cfa = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    14             string comm = cfa.AppSettings.Settings["commandfan"].Value;//这是得到风扇命令类
    15             Assembly assembly = Assembly.GetEntryAssembly();
    16             Command command =(Command) assembly.CreateInstance(comm);
    17             ButtonStart bs = new ButtonStart(command);//注入到调用者中
    18             bs.Start();//调用者执行调用,直接调用的是命令类对象的方法,实质最终的响应还是接收者完成
    19             Console.Read();
    20         }
    21     }
    22     class ButtonStart
    23     {
    24         private Command com = null;
    25         public ButtonStart(Command com)
    26         {
    27             this.com = com;
    28         }
    29         public void Start()
    30         {
    31             com.Execute();//执行命令类的方法
    32         }
    33     }
    34     abstract class Command
    35     {
    36         public abstract void Execute();
    37     }
    38     class FanCommand : Command//风扇命令类
    39     {
    40         private Fan fan = null;
    41         public FanCommand()
    42         {
    43             fan = new Fan();
    44         }
    45         public override void Execute()
    46         {
    47             fan.StartUP();
    48         }
    49     }
    50     class BulbCommand : Command
    51     {
    52         private Bulb bulb= null;
    53         public BulbCommand()
    54         {
    55             bulb = new Bulb();//调用命令接收者的业务方法
    56         }
    57         public override void Execute()
    58         {
    59             bulb.Light();//调用命令接收者的业务方法
    60         }
    61     }
    62     class Fan//风扇类,命令接收者
    63     {
    64         public void StartUP()
    65         {
    66             Console.WriteLine("风扇启动");
    67         }
    68     }
    69     class Bulb//灯泡类,命令接收者
    70     {
    71         public void Light()
    72         {
    73             Console.WriteLine("发光");
    74         }
    75     }
    76 }

      感觉实际上还是按一条链那样调用的样子。看不出太多的优势。

    命令队列,纪录日志,撤消操作

       命令队列适用的情况:当一个请求发出后,会有多个请求接收者响应,也就是有多个命令对象来“中间处理”;在命令发送者类中,维护一个命令列表,当请求发出时,依次调用命令队列中命令对象的方法。示例如下:

      

     1     class ButtonStart
     2     {
     3         private Command com = null;
     4         public List<Command> lstComm = new List<Command>();//维护命令队列
     5         public void StartAll()//启动所有命令
     6         {
     7             foreach (Command com in lstComm)
     8             {
     9                 com.Execute();
    10             }
    11         }
    12         public ButtonStart()
    13         {
    14         }
    15         public ButtonStart(Command com)
    16         {
    17             this.com = com;
    18         }
    19         public void Start()
    20         {
    21             com.Execute();//执行命令类的方法
    22         }
    23     }
    24 
    25 
    26 
    27 //客户端调用情况
    28             //命令队列
    29             ButtonStart bsque = new ButtonStart();
    30             bsque.lstComm.Add(new FanCommand());
    31             bsque.lstComm.Add(new BulbCommand());
    32             bsque.StartAll();
    33 
    34 /*
    35 在调用时,发送者类中的一次调用,就让所有命令对象来响应了,最终反映到所有接收者的响应中。
    36 这次调用,也体现到了多态的作用。
    37 */

      还可以把对多个命令的组织放到一个独立的对象中,对象对应的类结构大概如下:

     1     class QueueCommand
     2     {
     3         private List<Command> lstComm = new List<Command>();
     4         public void Add(Command com)//添加成员
     5         {
     6             lstComm.Add(com);
     7         }
     8         public void Execute()//执行此方法,循环调用多个命令对象的方法
     9         {
    10             foreach (Command com in lstComm)
    11             {
    12                 com.Execute();
    13             }
    14         }
    15     }

      纪录日志

      当一个命令执行前,把这个操作纪录下来。方法是在某个命令对象执行Excute方法时,在调用对应的接收者的业务方法前,把一些有纪录意义的文本保存到“日志文件”中。

     1     class BulbCommand : Command
     2     {
     3         public string blog = "发光日志";
     4         private Bulb bulb= null;
     5         public BulbCommand()
     6         {
     7             bulb = new Bulb();//调用命令接收者的业务方法
     8         }
     9         public override void Execute()
    10         {
    11             Console.WriteLine("模拟灯泡被开启日志"+blog);
    12             bulb.Light();//调用命令接收者的业务方法
    13         }
    14     }

      结合序列化等,把对象序列化到硬盘上。

      可撤消操作

      当一个命令对象执行Excute方法后,可以再调用一个与之相反的操作的方法就实现了撤消。比如加一个数后,保存此加数,让被加数送去加数,就实现一回撤消;如果实现多回撤消的话,把多次使用的加数保存到一个队列中,通过索引来得到某个加数,再用被减数减去它。

     1     class Command
     2     {
     3         public abstract int Execute(int x);
     4         public abstract int UnDo(int x);
     5     }
     6     class AddCommand : Command
     7     {
     8         private int value = 100;//传入的值和value相加操作
     9         public override int Execute(int x)
    10         {
    11             return x + value;
    12         }
    13         public override int UnDo(int x)
    14         {
    15             return x - value;
    16         }
    17     }

     

    什么时候可以用

       系统需要把请求发送者和接收者解耦;系统需要撤消操作、或者把请求处理排队。

     

     

  • 相关阅读:
    SQL SERVER常用取重复记录的SQL语句
    订单号生成
    SQL Server 2005中返回修改后的数据
    一条sql语句,要修改一个字段的俩个值,比如把字段sex中的男改为女,女改为男
    C#输入法全半角转换
    dataGridView1 筛选
    C#(WIN FORM)两个窗体间LISTVIEW值的修改
    ms sql server 2005数据库日志文件过大,需要清除或者清空
    SQL 判断表是否存在
    C#将数据写入记事本并且从记事本中读出
  • 原文地址:https://www.cnblogs.com/ddx-deng/p/3793878.html
Copyright © 2020-2023  润新知