Spiga

模式开发之旅(24):命令模式

2010-09-17 18:58:29

命令模式:将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。

落实到编码实现,命令模式用的最核心的实现手段,是将函数封装成对象。我们知道,C 语言支持函数指针,我们可以把函数当作变量传递来传递去。但是,在大部分编程语言中,函数没法儿作为参数传递给其他函数,也没法儿赋值给变量。借助命令模式,我们可以将函数封装成对象。具体来说就是,设计一个包含这个函数的类,实例化一个对象传来传去,这样就可以实现把函数像对象一样使用。从实现的角度来说,我们可以使用回调。

当我们把函数封装成对象之后,对象就可以存储下来,方便控制执行。所以,命令模式的主要作用和应用场景,是用来控制命令的执行,比如,异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等,这才是命令模式能发挥独一无二作用的地方。

命令模式实现

abstract class Command
{
    protected Receiver receiver;

    public Command(Receiver receiver)
    {
        this.receiver = receiver;
    }

    public abstract void Execute();
}

class ConcreteCommand : Command
{
    public ConcreteCommand(Receiver receiver) : base(receiver)
    { 
    }

    public override void Execute()
    {
        receiver.Action();
    }
}

class Invoker
{
    private Command command;
    public void SetCommand(Command command)
    {
        this.command = command;
    }

    public void ExecuteCommand()
    {
        command.Execute();
    }
}

class Receiver
{
    public void Action()
    {
        Console.WriteLine("执行请求");
    }
}

static void Main(string[] args)
{
    Receiver r = new Receiver();
    Command c = new ConcreteCommand(r);
    Invoker i = new Invoker();
    i.SetCommand(c);
    i.ExecuteCommand();

    Console.Read();
}

命令模式的作用

  • 它能较容易地设计一个命令队列
  • 在需要的情况下,可以较容易地将命令记入日志
  • 允许接受请求的一方决定是否要否决请求
  • 可以容易地实现对请求的撤销和重做
  • 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易

命令模式最关键的优点就是,命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。

命令模式 VS 策略模式

每个设计模式都应该由两部分组成:第一部分是应用场景,即这个模式可以解决哪类问题;第二部分是解决方案,即这个模式的设计思路和具体的代码实现。不过,代码实现并不是模式必须包含的。如果你单纯地只关注解决方案这一部分,甚至只关注代码实现,就会产生大部分模式看起来都很相似的错觉。

设计模式之间的主要区别还是在于设计意图,也就是应用场景。单纯地看设计思路或者代码实现,有些模式确实很相似,比如策略模式和工厂模式。

策略模式包含策略的定义、创建和使用三部分,从代码结构上来,它非常像工厂模式。它们的区别在于,策略模式侧重“策略”或“算法”这个特定的应用场景,用来解决根据运行时状态从一组策略中选择不同策略的问题,而工厂模式侧重封装对象的创建过程,这里的对象没有任何业务场景的限定,可以是策略,但也可以是其他东西。从设计意图上来,这两个模式完全是两回事儿。

在策略模式中,不同的策略具有相同的目的、不同的实现、互相之间可以替换。比如,BubbleSort、SelectionSort 都是为了实现排序的,只不过一个是用冒泡排序算法来实现的,另一个是用选择排序算法来实现的。而在命令模式中,不同的命令具有不同的目的,对应不同的处理逻辑,并且互相之间不可替换。