定义:
     将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。(网上很多地方引用的定义)
     将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。                     (Head First 的定义)
   解读: 请求说的更傻一点就是求别人为自己服务,对应到程序中,向别人提供服务的话好像离不开方法,请求大概就是对方法的调用了。不过请求这个词语,感觉有点怪怪。因为我调用B对象的C方法,不怎么像是向B请求C倒是像强制B执行C,B有不执行C的权利吗?(当开个玩笑)。提到参数化,就会想到"定义一个参数",参数说白了就是一个占位符、一个变量到时想放什么放什么。参数化就先理解成变量化、动态化吧。“从而使你可用不同的请求对客户进行参数化”这句话还是很难理解啊,关键是这个"客户".客户肯定是服务享受者嘛,那就应该是命令的调用者,好像不太合理。Head First 中有一句话,"一整天下来,女招待参数化了许多订单。这个对应到命令模式的理解就是命令传递着参数化命令对象,即命令对象(或者命令接口更合理吧)成为命令传递者的一个(组)成员,或其函数中的参数。再直接看看Head First中的定义,根据"一整天下来,女招待参数化了许多订单" 我们知道"其他对象"就是命令对象。使用不同请求来参数化命令对象,在这里请求理解成方法调用已经不合适了。把请求在程序中说到底就是一种命令,"命令对象"--就是命令接口,翻来覆去翻来覆去成了把命令接口动态的实例化成命令对象。晕死,写了这么多我当在写小品剧本。
再说一下封装,封装一般就是隐藏具体细节,提高独立性。有时候还可以见到把某某功能封装到一个对象,这个似乎有点像外包。算了打住打住。。。
http://www.javathinker.org/main.jsp?bc=showessay.jsp&filename=java/fengzhuang.htm

结构图


一个命令大概也就涉及到5个东西,命令发送者、命令传递者、命令本身(就是命令对象嘛)、命令执行者、命令执行结果(不考虑)。

描述:

    允许"发送请求的对象"和"接受并执行这些请求的对象分割开来"。算了受那个定义的打击我还是用自己的话补充一下吧,调用者和执行者之间相互解耦,命令对象中本身包含了执行者的信息。调用者只需要有一个命令对象,就可以完成他要的工作。执行者的每一种可能的操作都封装成一种命令,调用者识别的是命令的抽象。
这样调用者是独立于执行者的能力的增长、变化的。 (调用者对应类图下面的命令传递者吧)

实例分析:
下面我们来看看电风扇

 这是电风扇类

 class CeilingFan
    
{
        
public const int HIGHT = 3;
        
public const int MEDIUM = 2;
        
public const int LOW = 1;
        
public const int OFF = 0;

       // System.Collections.Generic.Stack
<ICommand> commandStack = new Stack<ICommand>();

        
public int Speed;
        
public void Hight()
        
{
            
this.Speed = HIGHT;
            Console.WriteLine(
"HIGHT");
        }

        
public void Low()
        
{
            
this.Speed = LOW;
            Console.WriteLine(
"Low");
        }

        
public void Medium()
        
{
            
this.Speed = MEDIUM;
            Console.WriteLine(
"medium");
        }

        
public void Off()
        
{
            
this.Speed = OFF;
            Console.WriteLine(
"Off");
        }

        
//public ICommand GetPreCommand()
        
//{
        
//    ICommand command = new NullCommand();
        
//    if (commandStack.Count > 1)
        
//    {
        
//        command = commandStack.Pop();
        
//    }
        
//    return command;
        
//}
        
//public bool HasNext()
        
//{
        
//    return this.commandStack.Count > 0;
        
//}
        
//public void CommandStatckAdd(ICommand command)
        
//{
        
//    this.commandStack.Push(command);
        
//}
        public int GetSpeed()
        
{
            
return Speed;
        }


    }
//命令接口  实现操作,和撤销功能。
 interface ICommand
    
{
         
void Execute();
         
void Undo();
    }

//命令对象具有电风扇的引用。CeilingFanHightCommand 是把电风扇调为高档的命令对象,对应还有中档 CeilingFanMediumCommand、低档、关闭对象
所有的实际操作都有电风扇自己完成。现在我们暂时不考虑撤销操作,也就是不用理会 IUndo 和 CeilingFanUndo;
 class CeilingFanHightCommand : ICommand
    
{
        CeilingFan ceilingFan;

        IUndo ceilingFanUndo 
= new CeilingFanUndo();

        
int perSpeed;

       
public CeilingFanHightCommand(CeilingFan ceilingFan)
        
{
            
this.ceilingFan = ceilingFan;
        }

        
public void Execute()
        
{
            perSpeed 
= ceilingFan.GetSpeed();
           
// ceilingFan.CommandStatckAdd(this);
            this.ceilingFan.Hight();
        }

        
public void Undo()
        
{
            ceilingFanUndo.Undo(perSpeed,ceilingFan);
        }


    }


测试代码:
 CeilingFan ceilingFan = new CeilingFan();

            CeilingFanHightCommand hightCommand 
= new CeilingFanHightCommand(ceilingFan);
            hightCommand.Execute();

            CeilingFanMediumCommand mediumCommand 
= new CeilingFanMediumCommand(ceilingFan);
            mediumCommand.Execute();

            CeilingFanLowCommand lowCommand 
= new CeilingFanLowCommand(ceilingFan);
            lowCommand.Execute();

            CeilingFanOffCommand offCommand 
= new CeilingFanOffCommand(ceilingFan);
            offCommand.Execute();

   看到这里好像没有发现调用者和执行者之间的解耦。 上面代码中有电风扇,有命令对象。测试代码应该在调用者中还是传递者中呢。


命令模式代码下载