【起源】
耦合存在于实体对象之间,也存在于实体对象与行为之间。
通常的方法调用,“行为请求者”和“行为实现者”之间呈现紧耦合。但在某些场合(如:需要对对行为进行“记录,undo/redo,事务”操作),需要松耦合。此时,将行为抽象为Command对象,置于“行为请求者”和“行为实现者”之间,使两者都依赖于Command对象。
【动机】
将一个请求封装为一个对象,从而使你可用不同的请求对Client进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
【核心】
调用方法需要两个要素:对象,方法名。对象确定数据,方法名确定操作,本质上是指定操作步骤,处理指定数据 。
通常的方式为:先指定对象,然后指定方法名,即“对象.方法名”,实现一个动作。
反过来想,也可以先指定方法名,后指定对象;但是由于方法属于某个对象,对象先于方法存在,所以要将方法单独封装到一个类中,将对象作为该类的参数传入,并用类的Execute方法封装“对象.方法名”。这样就在宏观上实现了“方法名(对象)”,实现相同的动作。
Command就是单独封装的那个类。这样做的另一个好处是:将动作变成了一个实体,可以控制它的执行时机 。如果不想只想执行动作,就不调用“动作.Execute()”,直到合适的时候,需要执行动作时调用“动作.Execute()”。
当行为变成一个实体对象后,就可以使用实体类的很多特性 ,比如:晚绑定。即:确定在何时会执行一个动作,但动作的具体内容在运行时指定。
Command对象是一个实体,“对象.方法名”是一个消息,内涵相同,承载的介质不同。
对象之间通过“消息”来通信,本质就是传递“动作”,通常是接受到“动作”就立即执行,Command模式将它分解为两个步骤:1.接收“动作” 2.选择时机执行。
【代码实例】
【模型图】
【Command与Delegate的异同】
Command:1.创建行为类 2.指定行为(抽象层面,粒度大) 3.以业务需要抽象方法,使执行时机延后并可管理;
Delegate:1.创建委托类代理某类方法(代码层面,粒度更小) 2.以函数签名抽象方法,将实现方式延后指定;
【delegate是什么】
抽象类 是对类的抽象(类包括:属性和行为);
接口 是对行为的抽象(行为包括:多个方法);
委托 是对方法的抽象(方法是:一个行为);
委托的使用:
1. 先定义委托类型 delegate void XX_Delegate() ;
2. 具体的方法 void XX_Method() ; void XX_Method2() ;
3. 定义变量引用该方法 XX_Delegate delegate1 = XX_Method ;
或: XX_Delegate delegate2 = new XX_Delegate(XX_Method) ;
4. 一个委托可绑定多个方法 delegate1 += XX_Method2 ;
5. 也可以取消已绑定的方法 delegate1 -= XX_Method2 ;
6. 通过事件可以封装委托,就像通过属性封装字段一样
public class Cat
{
public delegate void XX_Delegate() ;
public event XX_Delegate Cry;
}
在其它类中可以 “订阅” 这个事件
public class Mouse
{
public Mouse()
{
Cat.Cry += new XX_Delegate(this.Run);
}
void Run()
{
Console.Write("猫来了,跑之!");
}
}
在代码层面带来了什么?
1. 将行为实例化,使它可以作为实体来传递
2. 改变了对象间的通信方式,将“可变的动态过程”变成了“定义好的静态过程”。
原通信方式:A监控条件 --》满足条件,传递消息给B做处理
新通信方式:A监控条件 --》将A的消息与B的处理绑定(写命令) --》满足条件,发出消息(发出去执行)
好文:http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html
【Command和Delegate带来的意义】
原本只有“数据”是实体,可作为参数传递;
通过Command模式,“行为”也可变成实体;
C#提供了Delegate,“方法”也可变成实体;
实体是“看得见,摸得着”的,它们带来的意义是:将程序中的抽象部分变得具体,更利于理解和使用。