概述‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合[李建忠]。这就是本文要说的Command模式。‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
意图‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。[GOF 《设计模式》]‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
结构图‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Command模式结构图如下:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图1 ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Command模式结构图

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
生活中的例子‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Command模式将一个请求封装为一个对象,从而使你可以使用不同的请求对客户进行参数化。用餐时的账单是Command模式的一个例子。服务员接受顾客的点单,把它记在账单上封装。这个点单被排队等待烹饪。注意这里的"账单"是不依赖于菜单的,它可以被不同的顾客使用,因此它可以添入不同的点单项目。‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图2 ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
使用用餐例子的Command模式对象图

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Command模式解说‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
在众多的设计模式中,Command模式是很简单也很优雅的一种设计模式。Command模式它封装的是命令,把命令发出者的责任和命令执行者的责任分开。我们知道,一个类是一组操作和相应的一些变量的集合,现在有这样一个类Document,如下:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图3

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
示意性代码:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// 文档类‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class Document‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/// 显示操作‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Display()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Console.WriteLine(
"Display");‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/// 撤销操作‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Undo()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Console.WriteLine(
"Undo");‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/// 恢复操作‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Redo()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Console.WriteLine(
"Redo");‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

一般情况下我们使用这个类的时候,都会这样去写:

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class Program‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
static‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Main(string[] args)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Document doc
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new Document();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        doc.Display();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        doc.Undo();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        doc.Redo();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
这样的使用本来是没有任何问题的,但是我们看到在这个特定的应用中,出现了Undo/Redo的操作,这时如果行为的请求者和行为的实现者之间还是呈现这样一种紧耦合,就不太合适了。可以看到,客户程序是依赖于具体Document的命令(方法)的,引入Command模式,需要对Document中的三个命令进行抽象,这是Command模式最有意思的地方,因为在我们看来
Display(),Undo(),Redo()这三个方法都应该是Document所具有的,如果单独抽象出来成一个命令对象,那就是把函数层面的功能提到了类的层面,有点功能分解的味道,我觉得这正是Command模式解决这类问题的优雅之处,先对命令对象进行抽象:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图4

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
示意性代码:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// 抽象命令‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
abstract‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class DocumentCommand‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    Document _document;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public DocumentCommand(Document doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
this._document = doc;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
/// 执行‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
abstract‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Execute();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

其他的具体命令类都继承于该抽象类,如下:

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
图5

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
示意性代码:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// 显示命令‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class DisplayCommand : DocumentCommand‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public DisplayCommand(Document doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        :
base(doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{    ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
override‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Execute()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _document.Display();  ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// 撤销命令‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class UndoCommand : DocumentCommand‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{ ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public UndoCommand(Document doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        :
base(doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
override‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Execute()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _document.Undo();  ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// 重做命令‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class RedoCommand : DocumentCommand‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public RedoCommand(Document doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        :
base(doc)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{ ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
override‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Execute()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _document.Redo();  ‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
现在还需要一个Invoker角色的类,这其实相当于一个中间角色,前面我曾经说过,使用这样的一个中间层也是我们经常使用的手法,即把A对B的依赖转换为A对C的依赖。如下:
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图6

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
示意性代码:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// Invoker角色‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class DocumentInvoker‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    DocumentCommand _discmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    DocumentCommand _undcmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    DocumentCommand _redcmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public DocumentInvoker(DocumentCommand discmd,DocumentCommand undcmd,DocumentCommand redcmd)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
this._discmd = discmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
this._undcmd = undcmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
this._redcmd = redcmd;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Display()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _discmd.Execute();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Undo()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _undcmd.Execute();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Redo()‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        _redcmd.Execute();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

现在再来看客户程序的调用代码:

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class Program‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
static‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void Main(string[] args)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Document doc
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new Document();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        DocumentCommand discmd
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new DisplayCommand(doc);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        DocumentCommand undcmd
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new UndoCommand(doc);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        DocumentCommand redcmd
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new RedoCommand(doc);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        DocumentInvoker invoker
=‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
new DocumentInvoker(discmd,undcmd,redcmd);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        invoker.Display();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        invoker.Undo();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        invoker.Redo();‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

可以看到:

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
1.在客户程序中,不再依赖于Document的Display(),Undo(),Redo()命令,通过Command对这些命令进行了封装,使用它的一个关键就是抽象的Command类,它定义了一个操作的接口。同时我们也可以看到,本来这三个命令仅仅是三个方法而已,但是通过Command模式却把它们提到了类的层面,这其实是违背了面向对象的原则,但它却优雅的解决了分离命令的请求者和命令的执行者的问题,在使用Command模式的时候,一定要判断好使用它的时机。‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
2.上面的Undo/Redo只是简单示意性的实现,如果要实现这样的效果,需要对命令对象设置一个状态,由命令对象可以把状态存储起来。‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
.NET中的Command模式‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
在ASP.NET的MVC模式中,有一种叫Front Controller的模式,它分为Handler和Command树两个部分,Handler处理所有公共的逻辑,接收HTTP Post或Get请求以及相关的参数并根据输入的参数选择正确的命令对象,然后将控制权传递到Command对象,由其完成后面的操作,这里面其实就是用到了Command模式。‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图7‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Front Controller 的处理程序部分结构图

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

图8 Front Controller的命令部分结构图

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Handler 类负责处理各个 Web 请求,并将确定正确的 Command 对象这一职责委派给 CommandFactory 类。当 CommandFactory 返回 Command 对象后,Handler 将调用 Command 上的 Execute 方法来执行请求。具体的实现如下‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
Handler类:‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// Handler类‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
class Handler : IHttpHandler‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
void ProcessRequest(HttpContext context)‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        Command command
= CommandFactory.Make(context.Request.Params);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        command.Execute(context);‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
public‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
bool IsReusable‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
   
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
get‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
       
{‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
           
return‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
true;‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
        }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
    }
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
}
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ

Command接口:

‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/**////‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
<summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
/// Command‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
///‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
</summary>‡vډ »Äùøwww.netcsharp.cn:<åƒažõ
‡vډ »Äùøwww.netcsharp.cn:<åƒažõ