> 话说,《西游记》中有这样一段故事,玉帝命令太白金星召美猴王上天:"金星径入水帘洞当中,面南立定道:我是西方太白金星,奉玉帝招安圣旨,请你上界报道,拜受仙录。具体对话内容如下所示:
> 太白金星:大圣,我主玉帝听说你才能出众,对你非常期待啊。
> 孙大圣:是么,真的?
> 太白金星:上界众仙也很仰慕大圣你啊。
> 孙大圣:这......
> 太白金星:大圣还犹豫是么?
> 孙大圣:我去做什么?
> 太白金星:绝对一把手,你的地盘好像很大,具体上去就知道了。
> 孙大圣:那我去看看也好。
> 太白金星:哈哈,大圣,请!
今天我们的设计模式就从孙大圣上界报道开始说起---命令模式,即将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。
命令模式属于行为模式。意图是将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求的排队或记录请求的日志,以及支持可以撤销的操作。又叫动作(Action)或者事务(Transaction)。有时必须向一个对象提交请求,但是并不知道关于被请求的操作或者请求的接受者的任何信息。命令模式通过将请求本身变成一个对象来使工具箱对象可向未指定的应用对象提出请求,这个对象可以被存储并像其他的对象一样被传递,这一个模式的关键是抽象的Command类,它定义了一个执行操作的接口,其最简单的形式是一个抽象的Execute操作,具体的Command子类将接收者作为其一个实例变量,并实现Execute操作,制定接收者采取的动作,而接收者有执行该请求所需的具体信息。这就是命令模式(Command Pattern)首先来看一下命令模式的结构图:
![](https://box.kancloud.cn/2015-12-30_568374417875a.jpg)
来分析一下,孙悟空上界报道中的逻辑关系,'"玉帝是系统的客户端,太白金星是命令的发出者,猴王是命令的接收者,圣旨就是命令。玉帝的这一道命令就是要求猴王到上界报到。玉帝只管发出命令,而不管命令是怎样传达到美猴王的。太白金星负责将圣旨传到,可是美猴王怎么执行圣旨、何时执行圣旨是美猴王自己的事。来看一下代码实现:
~~~
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ImperialEdict i = new ImperialEdict();
Command c = new ReportCommand();
Venus v = new Venus();
v.ObtainOrder();
v.ExcuteCommand();
Console.Read();
}
}
//抽象命令类
//抽象命令
public abstract class Command
{
protected Imperial receiver;
public Command(Imperial receiver)
{
this.receiver = receiver;
}
//执行命令
abstract public void ExcuteCommand();
}
//具体命令类
//上界报到命令
class ReportCommand : Imperial
{
public ReportCommand(Imperial receiver)
:base(receiver)
{ }
public override void ExcuteCommand()
{
receiver.Report();
}
}
//太白金星
public class Venus
{
private Imperial command;
//收到命令
public void ObtainOrder(Imperial command)
{
this.command =command ;
}
//执行命令
public void Notify()
{
command.ExcuteCommand ();
}
}
//猴王
public class MonkeyKing
{
//上界报道
public void Imperial()
{
Console .WriteLine ("上界报道!");
}
}
}
~~~
对于命令模式,我们可以这样理解,提供一个抽象的Command接口,将执行命令操作的方法封装到Command类接口中,ConcreteCommand实现这个Command接口方法,通过调用Receiver实例变量处理请求。客户端定义一个Invoker对象存储该concreteCommand对象,该invoker通过调用command对象的递交一个请求。