定义:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。(网上很多地方引用的定义)
将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。 (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个东西,命令发送者、命令传递者、命令本身(就是命令对象嘛)、命令执行者、命令执行结果(不考虑)。
描述:
允许"发送请求的对象"和"接受并执行这些请求的对象分割开来"。算了受那个定义的打击我还是用自己的话补充一下吧,调用者和执行者之间相互解耦,命令对象中本身包含了执行者的信息。调用者只需要有一个命令对象,就可以完成他要的工作。执行者的每一种可能的操作都封装成一种命令,调用者识别的是命令的抽象。
这样调用者是独立于执行者的能力的增长、变化的。 (调用者对应类图下面的命令传递者吧)
实例分析:
下面我们来看看电风扇
这是电风扇类
{
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;
}
}
{
void Execute();
void Undo();
}
//命令对象具有电风扇的引用。CeilingFanHightCommand 是把电风扇调为高档的命令对象,对应还有中档 CeilingFanMediumCommand、低档、关闭对象
所有的实际操作都有电风扇自己完成。现在我们暂时不考虑撤销操作,也就是不用理会 IUndo 和 CeilingFanUndo;
{
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);
}
}
测试代码:
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();
看到这里好像没有发现调用者和执行者之间的解耦。 上面代码中有电风扇,有命令对象。测试代码应该在调用者中还是传递者中呢。
命令模式代码下载