温故知新(10)——命令模式
<div id="cnblogs_post_body">概述虽然并不完全符合,命令模式给我的感觉有点像数据库中的中间表。中间表将两个实体表的主键作为外键,将两个实体表关联成多对多的关系。同样命令模式中命令对象就好像中间表一样,将动作的引发者和动作的执行者关联起来,引发者无需知道执行者,执行者也无需了解是谁引发了这个动作。如果仔细想想,动作的引发者和动作的执行者之间也是多对多的关系。下面是GOF给出的意图:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
这局意图的前半句,个人感觉有些描述得过于抽象,这里仅供参考;后半句怎说明了命令模式的的一些应用场景和用途:
1、可以在对象关系上解耦动作的引发者和动作的执行者;
2、可以在时间上解耦动作的引发和动作的执行;
3、可以实现动作的“撤销”和“重做”,也可以实现“修改日志”,当系统崩溃时,这些修改可以被重做一遍。
4、将一组动作实现为一个事物。
实现命令模式时需要考虑的一个问题是,命令对象的“轻”或“重”,“轻”模式时,命令对象只负责将动作的引发者和动作的执行者关联起来;而“重”模式时,命令对象自身会包含处理逻辑。个人认为通常应该将命令对象实现为“轻”模式,而在一些无需动作的执行者的特殊情况下将命令对象实现为“重”模式。
命令模式可以与组合模式结合,即用组合模式将命令对象组合成复合命令对象。
结构
命令模式是一种比较灵活的模式,下面是经典命令模式的类图:
http://images.cnblogs.com/cnblogs_com/zdy_bit/201209/201209251515079575.png
模式的参与者:
1、命令接口,所有命令对象须实现此抽象——ICommand;
2、具体的命令,命令通常包含一个动作执行者——Command;
3、引发动作的对象,经常是UI组件或定时组件——Invoker;
4、动作的实际执行者——Receiver;
5、创建命令并设置接收者——Client;
上图中,除ICommand接口以外,每个参与者都有可能存在多个。
示例
系统中有很多批处理的任务,比如定期数据清理与备份,定期对某些数值进行一些计算等等,这些动作通常由一个对象(比如一个定时器)来调度,不同的动作也由不同的对象去执行。这些的动作的经常会发生增减,因此让调度对象包含所有执行者的引用,直接调用的执行者的方法,是不太现实的。同样由于希望动作的触发与动作的执行,希望构成异步,因此使用命令模式,将这些动作包装成命令对象,由这些命令对象包含具体的动作执行者的做法是可行的。
由于是一个说明性示例,所以下面的代码忽略了定时调度、多线程等具体实现。
.codearea{ color:black;background-color:white;line-height:18px;border:1px solid #4f81bd;margin:0;width:auto !important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family: "Courier New","Consolas","Fixedsys","BitStream Vera Sans Mono", courier,monospace,serif}.codearea pre{ color:black; line-height:18px;padding:0 0 0 12px !important; margin:0em;background-color:#fff !important}.linewrap pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}.codearea pre.alt{ background-color:#f7f7ff !important}.codearea .lnum{color:#4f81bd;line-height:18px}1、动作执行者,下面提供两个。
计算器Calculater。
<div class="codearea linewrap"> 1:using System; 2: 3:namespace DesignPatterns.Command 4:{ 5: /// <summary> 6: /// 计算器 7: /// </summary> 8: public class Calculater 9: {10: public void Calculate()11: {12: Console.WriteLine("计算操作");13: }14: }15:}16:
页:
[1]