c#中命令模式详解

这篇具有很好参考价值的文章主要介绍了c#中命令模式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基本介绍: 

  命令模式,顾名思义就是将命令抽象化,然后将请求者和接收者通过命令进行绑定。

  而命令的请求者只管下达命令,命令的接收者只管执行命令。

  从而实现了解耦,请求者和接受者二者相对独立。

  单独理解起来比较困难,咱们还是通过具体实例来说明吧。

举例说明:

  生活中遥控控制电器就是命令模式,比如智能开关控制一盏灯。

  首先将灯的开和关封装成一个命令,然后将这个命令绑定到智能开关上。

  智能开关的执行其实就是灯开关的执行,灯和智能开关是通过命令来进行交互的。

  这个时候如果想控制电视的开关,那就可以将电视的开关封装成一个命令。

  然后将这个命令绑定到智能开关上,智能开关的执行这个时候就变成了电视的开关。

  如果即想控制电视又想控制灯,那就可以将灯的命令和电视的命令都绑定到智能开关上。

 

  又比如皇帝写了一道圣旨,命令张三即刻回京。

  圣旨跟张三是绑定关系,也就是说张三是实际执行者,圣旨是命令,起到的作用就是跟张三进行绑定和传达信息。

  那想个问题传达圣旨的宦官是谁有关系吗,是没有的,是谁都可以。但又是不可或缺的。它就相当于一个遥控或者说是中间人、传话人。

  是皇帝将这个宦官和圣旨进行了绑定(客户端就是那个皇帝)。那在想个问题,是先有圣旨再有张三呢,还是先有张三再有圣旨。

  答案是肯定的,先有张三,也就是说得先有具体执行者。

  然后再有圣旨即命令,通过名字将张三和圣旨绑定到一起。

  如果皇帝想命令李四也回京,那这个圣旨可以命令李四吗?是不可以的,需要重新写一份圣旨。

  所以从这个不难看出,命令类和具体的执行者是强绑定关系,当然也可以做成工厂。

  这个时候大家想个问题,两道圣旨是不是可以让同一个宦官去传达就可以。因为宦官和执行者不存在绑定,它只和圣旨绑定。

  所以说宦官就相当于遥控,它只需要宣读圣旨而不必在意具体是怎么执行的,就可以让不同的执行人进行不同的操作。

  这就是命令模式的本质。

基本结构:

  通过上述例子不难看出,命令模式主要核心构件有以下几个:

  ◊ 命令的执行者(接收者Receiver):它单纯的只具体实现了功能。(实例中对应的则是张三和李四)

  ◊ 命令的下达者(调用者Invoker)

    就是起到遥控的作用,首先在类中声明抽象命令类的引用,并通过参数注入等方式进行实例化。

    然后通过调用命令对象来告诉执行者执行功能。起到一个传声筒的作用。(实例中对应的是宦官)

  ◊ 抽象命令类Command

    主要作用有两点,其一就是为了规范具体命令类,声明其执行方法。

    其二就是为了方便调用者Invoker调用,使其不需要知道具体命令类,只需要执行抽象命令类即可。(实例中对应的是泛指圣旨)

  ◊ 具体命令类ConcreteCommand

    继承自抽象类,在类中首先声明了执行者的引用,通过参数注入等方式进行创建执行者对象,将命令类和执行者进行绑定。

    其次具体实现了抽象类中声明的执行方法,调用执行者对象中方法进行执行。(实例中对应的是张三和李四具体的两道圣旨)

  ◊ 客户端角色Client

    主要是负责将执行者和命令类进行绑定,其次将命令类和调用者进行绑定。

    使其调用者可以通过命令类给执行者传递消息进行执行。(实例中对应的是皇帝角色)

优缺点:

  优点

    1.降低了系统的耦合性。将调用操作对象和知道如何实现该操作对象的解耦。

    2.通过命令模式,新的命令可以很轻松的加入系统中,且不会影响其他类,符合开闭原则。

  缺点

    使用命令模式可能会导致某些系统存在过多的命令类,会影响使用。

  命令模式适用情形

    1.将用户界面和行为分离。

    2.对请求进行排队,记录请求日志以及支持可撤销的操作等。

具体实例:

  就以皇帝下达圣旨作为实例吧,首先先说下顺序。

    1.得先有执行者也就是接收圣旨的人,它主要是执行具体的行为和功能,如果是遥控控制灯,那这里就是那盏灯本身。这里命名为Receiver_ZhangSan类。

    2.其次就需要创建圣旨,也就是传达命令的媒介。但每道圣旨都是一样的材质和规则,所以需要先创建一个抽象类来规范。这里将抽象类命名为Command类,将具体命令类即圣旨内容命名为ConcreteCommand类它继承自抽象类。

    3.有了执行人也有了圣旨,那就可以安排一个传旨的人就可以了(如果是遥控控制灯,这里相当于遥控)。这里命名为Invoker类。

    4.执行人有了,圣旨有了,传旨的人也有了,那皇帝就可以下令执行了。这里就相当于客户端调用了。

  实现方式说明:

    1.创建Receiver_ZhangSan类,设置具体执行方法,这里可以是骑马回京,可以是其他的操作。它只负责具体功能的实现。

    2.创建Command抽象类,声明Execute方法。

    3.创建ConcreteCommand命令类,继承自抽象类。在该类中创建Receiver_ZhangSan类的引用,并通过参数注入或属性赋值等方式实例化该类,并在Execute方法中具体调用该类中的具体实现方法。

    4.创建Invoker类,在该类中创建Command抽象类的引用,并通过参数注入或属性赋值等方式将ConcreteCommand类实例化,并在该类中创建方法来执行抽象类中的Execute方法。

    5.客户端直接调用Invoker类中的方法来执行命令。

    具体的执行过程就是,通过Invoker类中的方法来调用抽象类中的Execute方法其实就是调用ConcreteCommand中的Execute方法,

    然后ConcreteCommand中的Execute调用的又是Receiver_ZhangSan类中的具体实现方法。

    这样就相当于通过Invoker类调用了Receiver_ZhangSan类中的方法,只不过是中间加了一个传话人即命令类。

  为什么这么做呢?这样做有什么好处呢?

    好处也很好理解,那就是Invoker类不必知道具体执行人是谁,也不必知道具体怎么执行,只需要将命令注入给该类就好了。

    这样如果命令改变了,那直接改变注入的命令类就可以了,方便快捷,而且不需要修改现有的类,符合开闭原则。

    而且还可以按顺序批量执行命令,只需要将命令依次注入给Invoker类进行调用就可以了。即任务队列。

    也可以一次性注入多条命令,同时执行。

 1     /// <summary>
 2     /// 张三类,它是实际执行者,也就是命令接收者
 3     /// </summary>
 4     public class Receiver_ZhangSan
 5     {
 6         private string strName = "张三";
 7         public void Eat()
 8         {
 9             Console.WriteLine(strName + ":吃饭。");
10         }
11         public void Behavior1()
12         {
13             Console.WriteLine(strName + ":骑马回京。");
14         }
15         public void Behavior2()
16         {
17             Console.WriteLine(strName + ":原地待命。");
18         }
19     }
20 
21     /// <summary>
22     /// 命令抽象类,规范命令类,并提供执行方法。
23     /// </summary>
24     public abstract class Command
25     {
26         //执行方法
27         public abstract void Execute();
28     }
29 
30     /// <summary>
31     /// 具体命令类,也就是圣旨书写的具体内容。
32     /// </summary>
33     public class ConcreteCommand1 : Command
34     {
35         //创建执行人的引用,这里使用readonly,规定只可以在构造函数中进行赋值。
36         private readonly Receiver_ZhangSan _Receiver_ZhangSan;
37 
38         //构造函数,参数注入方式,将执行人注入到命令类中。好比是将人名写在圣旨上。
39         public ConcreteCommand1(Receiver_ZhangSan receiver_ZhangSan)
40         {
41             this._Receiver_ZhangSan = receiver_ZhangSan;
42         }
43 
44         //具体命令
45         public override void Execute()
46         {
47             //下达立刻回京的命令
48             this._Receiver_ZhangSan.Behavior1();
49         }
50     }
51 
52     /// <summary>
53     /// 调用者类,命令下达者,即宦官。
54     /// </summary>
55     public class Invoker
56     {
57         //创建抽象命令类的引用,这里不同于具体命令类,方便演示,使用了参数赋值的形式进行注入。
58         public Command command { get; set; }
59 
60         //下达命令,即宣读圣旨
61         public void Reading()
62         {
63             if (command != null)
64             {
65                 command.Execute();
66             }
67         }
68     }
69 
70     /// <summary>
71     /// 客户端
72     /// </summary>
73     class Client
74     {
75         static void Main(string[] args)
76         {
77             //首先创建接收人,即张三。
78             Receiver_ZhangSan receiver_ZhangSan = new Receiver_ZhangSan();
79 
80             //然后创建命令类,即圣旨。这里通过构造函数参数注入的形式将张三和命令进行绑定。
81             Command command = new ConcreteCommand1(receiver_ZhangSan);
82 
83             //其次创建调用者,即宦官。
84             Invoker invoker = new Invoker();
85             //为了演示不同注入方式,这里通过属性赋值的方式将命令和调用者绑定。
86             invoker.command = command;
87 
88             //调用,即宣读圣旨
89             invoker.Reading();
90 
91             Console.WriteLine("\r\n");
92 
93             Console.ReadKey();
94         }
95     }

c#中命令模式详解

  如果皇帝想让张三吃饱饭再回京,同时想让李四原地待命该如何实现呢。

  两种方式,如果张三和李四在一起,就可以写在一个圣旨里即写在一个命令类里。

  如果不在一起,那就需要写两道圣旨,即两个命令类。

添加李四类:

 1     /// <summary>
 2     /// 李四类,它是实际执行者,也就是命令接收者
 3     /// </summary>
 4     public class Receiver_LiSi
 5     {
 6         private string strName = "李四";
 7         public void Eat()
 8         {
 9             Console.WriteLine(strName + ":吃饭。");
10         }
11         public void Behavior1()
12         {
13             Console.WriteLine(strName + ":坐马车回京。");
14         }
15         public void Behavior2()
16         {
17             Console.WriteLine(strName + ":原地待命。");
18         }
19     }

添加新命令类:

 1     /// <summary>
 2     /// 圣旨,即命令类
 3     /// </summary>
 4     public class ConcreteCommand3 : Command
 5     {
 6         //创建执行人的引用
 7         private readonly Receiver_LiSi _Receiver_LiSi;
 8         private readonly Receiver_ZhangSan _Receiver_ZhangSan;
 9 
10         //将执行人注入到命令类中。
11         public ConcreteCommand3(Receiver_LiSi receiver_LiSi, Receiver_ZhangSan receiver_ZhangSan)
12         {
13             this._Receiver_LiSi = receiver_LiSi;
14             this._Receiver_ZhangSan = receiver_ZhangSan;
15         }
16 
17         //具体命令
18         public override void Execute()
19         {
20             //让张三吃饱饭再回京
21             this._Receiver_ZhangSan.Eat();
22             this._Receiver_ZhangSan.Behavior1();
23             //让李四原地待命
24             this._Receiver_LiSi.Behavior2();
25         }
26     }

客户端调用:

 1     /// <summary>
 2     /// 客户端
 3     /// </summary>
 4     class Client
 5     {
 6         static void Main(string[] args)
 7         {
 8             //首先创建接收人,即张三和李四。
 9             Receiver_ZhangSan receiver_ZhangSan = new Receiver_ZhangSan();
10             Receiver_LiSi receiver_LiSi = new Receiver_LiSi();
11 
12             //然后创建命令类,即圣旨。这里通过构造函数参数注入的形式将张三和命令进行绑定。
13             Command command = new ConcreteCommand3(receiver_LiSi, receiver_ZhangSan);
14 
15             //其次创建调用者,即宦官。
16             Invoker invoker = new Invoker();
17             //为了演示不同注入方式,这里通过属性赋值的方式将命令和调用者绑定。
18             invoker.command = command;
19 
20             //调用,即宣读圣旨
21             invoker.Reading();
22 
23             Console.WriteLine("\r\n");
24 
25             Console.ReadKey();
26         }
27     }

c#中命令模式详解

   以上实例则是张三和李四在一起,写在一个圣旨里即写在一个命令类里。如果不在一起呢?

创建新命令类:

 1     /// <summary>
 2     /// 让李四原地待命的圣旨
 3     /// </summary>
 4     public class ConcreteCommand2 : Command
 5     {
 6         //创建执行人的引用
 7         private readonly Receiver_LiSi _Receiver_LiSi;
 8 
 9         //将执行人注入到命令类中。
10         public ConcreteCommand2(Receiver_LiSi receiver_LiSi)
11         {
12             this._Receiver_LiSi = receiver_LiSi;
13         }
14 
15         //具体命令
16         public override void Execute()
17         {
18             //让李四原地待命
19             this._Receiver_LiSi.Behavior2();
20         }
21     }

客户端调用:

 1     /// <summary>
 2     /// 客户端
 3     /// </summary>
 4     class Client
 5     {
 6         static void Main(string[] args)
 7         {
 8             //首先创建接收人,即张三和李四。
 9             Receiver_ZhangSan receiver_ZhangSan = new Receiver_ZhangSan();
10             Receiver_LiSi receiver_LiSi = new Receiver_LiSi();
11 
12             //然后创建命令类,即圣旨1
13             Command command1 = new ConcreteCommand1(receiver_ZhangSan);
14             //然后创建命令类,即圣旨2
15             Command command2 = new ConcreteCommand2(receiver_LiSi);
16 
17             //其次创建调用者,即宦官。
18             Invoker invoker = new Invoker();
19             invoker.command = command1;
20             invoker.Reading();
21 
22             invoker.command = command2;
23             invoker.Reading();
24 
25             Console.WriteLine("\r\n");
26 
27             Console.ReadKey();
28         }
29     }

c#中命令模式详解

   另一种方式,可以在Invoker里申明数组保存命令依次执行。

 1     /// <summary>
 2     /// 调用者类,命令下达者,即宦官。
 3     /// </summary>
 4     public class InvokerList
 5     {
 6         public List<Command> commands;
 7         public void AddCommand(Command command)
 8         {
 9             if (commands == null)
10             {
11                 commands = new List<Command>();
12             }
13             commands.Add(command);
14         }
15 
16         //下达命令,即宣读圣旨
17         public void Reading()
18         {
19             if (commands != null)
20             {
21                 foreach (Command item in commands)
22                 {
23                     item.Execute();
24                 }
25             }
26         }
27     }

客户端调用:

 1     /// <summary>
 2     /// 客户端
 3     /// </summary>
 4     class Client
 5     {
 6         static void Main(string[] args)
 7         {
 8             //首先创建接收人,即张三和李四。
 9             Receiver_ZhangSan receiver_ZhangSan = new Receiver_ZhangSan();
10             Receiver_LiSi receiver_LiSi = new Receiver_LiSi();
11 
12             //然后创建命令类,即圣旨1
13             Command command1 = new ConcreteCommand1(receiver_ZhangSan);
14             //然后创建命令类,即圣旨2
15             Command command2 = new ConcreteCommand2(receiver_LiSi);
16 
17             //其次创建调用者,即宦官。
18             InvokerList invoker = new InvokerList();
19             invoker.AddCommand(command1);
20             invoker.AddCommand(command2);
21             invoker.Reading();
22 
23             Console.WriteLine("\r\n");
24 
25             Console.ReadKey();
26         }
27     }

c#中命令模式详解

从以上事例中不难看出,命令的调用者即Invoker类无需知道执行人和具体执行什么内容,更换命令也很方便,只需要改变注入的命令类就可以了。

但也可以从实例中看出,新增一个命令就需要新增一个命令类,这可能会导致某些系统存在过多的命令类,会影响使用。

  读后思考:书读百遍其义自见,读不够百遍,那不如自己动手写写,不如就拿遥控控制不同电器为例子。

  友情提示:
      创建一盏灯
      创建一个命令,该命令控制继承自抽象类,执行灯的一些操作,所以需要将创建好的灯注入到命令对象里。
      创建一个遥控,将遥控的某一个按钮绑定上该命令。可以是参数注入,也可以是属性赋值。
      具体执行就是执行遥控的函数,然后传递到命令类 最后才是具体灯的操作。

      关键点就是灯跟命令进行绑定,方式就是在命令里声明一个灯的引用,然后参数注入等方式进行实例化。
      然后命令再跟遥控进行绑定,方式相同,在遥控里声明一个命令的引用,然后参数注入等方式进行实例化。
      最后实行执行操作的是遥控。

      为什么要将命令抽象化,因为要跟遥控绑定,遥控只是执行命令,具体是什么样的命令,就交给命令本身去决定了。
      还有一个问题就是,有多少个电器 就需要多少个命令 。那其实可以合并成一个。大家可以动手试试。

总结:

  将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。适用于需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。

  命令模式的实现要点在于把某个具体的命令抽象化为具体的命令类,并通过加入命令请求者角色来实现将命令发送者对命令执行者的依赖分割开。

  命令模式的目的是解除命令发出者和接收者之间的紧密耦合关系,使二者相对独立,有利于程序的并行开发和代码的维护。

  命令模式的核心思想是将请求封装为一个对象,将其作为命令发起者和接收者的中介,而抽象出来的命令对象又使得能够对一系列请求进行操作,如对请求进行排队,记录请求日志以及支持可撤销的操作等。

  文章来源地址https://www.toymoban.com/news/detail-746219.html

到了这里,关于c#中命令模式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c#中原型模式详解

    基础介绍:    具体可分为2个角色:     Prototype(原型类):声明一个Clone自身的接口;     ConcretePrototype(具体原型类):,实现一个Clone自身的操作。 在原型模式中,Prototype通常提供一个包含Clone方法的接口,具体的原型ConcretePrototype使用Clone方法完成对象的创

    2024年02月05日
    浏览(42)
  • c#组合模式详解

    基础介绍:   组合模式用于表示 部分-整体 的 层次结构 。适用于希望用户 忽略 组合对象与单个对象的 不同 ,用户将 统一地使用 组合结构中的 所有对象 的情况。   顾名思义,什么叫部分-整体,比如常见的前端UI,一个DIV标签中可以存在多个A标签、P标签、DIV标签等

    2024年02月05日
    浏览(38)
  • c#桥接模式详解

    基础介绍:   将 抽象部分 与它的 实现部分 分离,使它们都可以 独立地变化 。适用于不希望在抽象和实现部分之间有固定的绑定关系的情况,或者类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充的情况。   将抽象部分与实现部分分离,使它们都可以独

    2024年02月05日
    浏览(28)
  • c#享元模式详解

    基本介绍:   享元模式的定义: 运用 共享技术 有效地支持 大量 细粒度的 对象重复使用 。适用于大量小粒度的对象造成的运行效率和内存使用效率低下的情况。   “享元”顾名思义,“享” 共享 的意思,“元” 单元 ,最小对象,零部件的意思。   即从字面意思

    2024年02月06日
    浏览(32)
  • c#中工厂模式详解

    总体介绍:   工厂模式主要有三种类型: 简单工厂 、 工厂方法 和 抽象工厂 ,该模式用于 封装 和 管理对象的创建 ,是一种 创建型模式 。   万物皆对象,创建对象时必然需要new该对象,当需要更改对象时,需要把项目中所有地方都修改一遍,这显然违背了软件设计

    2024年02月06日
    浏览(23)
  • c#装饰器模式详解

    基础介绍:    动态地给一个对象添加一些额外的职责。适用于需要扩展一个类的功能,或给一个类添加多个变化的情况。   装饰器,顾名思义就是在原有基础上添加一些功能。   大家都只知道如果想单纯的给原有类增加一些功能,可以直接继续该类生成一个子类就可

    2024年02月05日
    浏览(32)
  • c#中代理模式详解

    基本介绍:   “代理”顾名思义指以他人的名义,在授权范围内进行处理事情的意思。   在编程语言中的则解释为:为其他对象提供一种代理以控制对这个对象的访问。   从释义上不难解读,代理本质就是一个中介,客户通过中介来访问原对象。本质就是在原对象基

    2024年02月05日
    浏览(37)
  • c#中责任链模式详解

    基本介绍:   “责任链”顾名思义,是指一个需要 负责处理请求的链条 。    每个 链条 节点 都是一个 单独的责任者 ,由 责任者自己决定 是否 处理请求或交给下一个节点 。   在设计模式中的解释则为: 为请求创建了一个接收者对象的链 。适用于有 多个对象可以

    2024年02月05日
    浏览(70)
  • c#中单例模式详解

    基础介绍:    确保一个类只有一个实例,并提供一个全局访问点。   适用于需要频繁实例化然后销毁的对象,创建对象消耗资源过多,但又经常用到的对象,频繁访问数据库或文件的对象。    其本质就是保证在 整个应用程序 的 生命周期 中, 任何一个时刻,单例类

    2024年02月06日
    浏览(44)
  • Vim学习(一)——基本命令与三种模式

    写在前面, 8月3日,Vim创始人Bram Moolenaar去世,在此向老爷子致敬!感谢他为这个世界带来的优秀编辑器Vim。 Vim全称叫Vi IMproved. 而vi则是Visual Interface的缩写,他们处理都是ASCII码字符数据;vim 是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语

    2024年02月13日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包