设计模式系列漫谈之七 - 命令模式
故事
小时候,我梦想自己成为一名真正的军人,对军营生活充满着向往.,军人的豪气,军人的英姿总给人无限遐想。闲暇之余,我喜欢看看军事题材的电视剧,包括《和平年代》、《历史的天空》、《沙场点兵》、《中国近卫军》、《垂直打击》、《石破天惊》、《铁色高原》。今年一部电视剧《士兵突击》再次让农村出身的傻根成为2007年最耀眼的明星。
我想,大多数读过大学的人都经历过一段艰苦的军训生活(其实根本不算苦)。虽然这种军训每天也只是练练军姿,走走正步而已,但是还是觉得有点新鲜感。当时,在所有的教官中,我们的教官是最帅气的。大家还开玩笑说,他必将会成为我们学校所有女生的梦中情人。另外,他的嗓门特别大,立正! 稍息!向左转! 向右转!那声音简直是震耳欲聋!
军人以服从命令为天职。立正! 稍息!向左转! 向右转!
命令模式(Command)的解决方案
GOF在《设计模式》中对命令模式描述:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。命令模式中需要定义的角色:命令接收者(Receiver)、命令抽象类(Command)、具体命令对象(LZCommand/SXCommand/XZZCommand/XYZCommand)、命令执行者(Invoker)。
命令接收者对象如下:
{
public class Receiver
{
public Receiver()
{
}
public void LZ()
{
//立正;
}
public void SX()
{
//稍息;
}
public void XZZ()
{
//向左转;
}
public void XYZ()
{
//向右转;
}
}
}
命令抽象类如下:
{
public abstract class Command
{
protected Receiver _receiver=null;
public Command(Receiver receiver)
{
this._receiver=receiver;
}
public abstract void Execute();
}
}
命令具体对象如下:
{
public class LZCommand:Command
{
public LZCommand(Receiver receiver):base(receiver)
{
}
public override void Execute()
{
receiver.LZ();
}
}
public class SXCommand:Command
{
public SXCommand(Receiver receiver):base(receiver)
{
}
public override void Execute()
{
receiver.SX();
}
}
public class XZZCommand:ICommand
{
public XZZCommand(Receiver receiver):base(receiver)
{
}
public override void Execute()
{
receiver.XZZ();
}
}
public class XZZCommand:ICommand
{
public XYZCommand(Receiver receiver):base(receiver)
{
}
public override void Execute()
{
receiver.XYZ();
}
}
}
命令执行者对象如下:
{
public class Invoker
{
private ICommand _lz;
private ICommand _sx;
private ICommand _xzz;
private ICommand _xyz;
public Invoker(ICommand lz,ICommand sx,ICommand xzz,ICommand xyz)
{
this._lz=lz;
this._sx=sx;
this._xzz=zz;
this._xyz=yz;
}
public void LZ()
{
this._lz.Execute();
}
public void SX()
{
this._sx.Execute();
}
public void XZZ()
{
this._xzz.Execute();
}
public void XYZ()
{
this._xyz.Execute();
}
}
}
接下来,我们通过客户端进行调用。假如我们创建一个窗体,窗体上放置四个按钮,如下图:
调用代码如下:
{
private void Form1_Load(object sender, EventArgs e)
{
Receiver rec=new Receiver();
LZCommand lzCommand=new LZCommand(rec);
SXCommand sxCommand=new SXCommand(rec);
XZZCommand xzzCommand=new XZZCommand(rec);
XYZCommand xyzCommand=new XYZCommand(rec);
Invoker invoker=new Invoker(lzCommand,sxCommand,xzzCommand,xyzCommand);
}
private void btnLZ_Click(object sender, EventArgs e)
{
invoker.LZ();
}
private void btnSX_Click(object sender, EventArgs e)
{
invoker.SX();
}
private void btnXZZ_Click(object sender, EventArgs e)
{
invoker.XZZ();
}
private void btnXYZ_Click(object sender, EventArgs e)
{
invoker.XYZ();
}
}
最后一个问题,如果我要增加一个命令按钮“向后转”,怎么办呢?我们可以认为,向左转 + 向左转=向后转,所以实现如下:
invoker.XZZ();
invoker.XZZ();
当然这样的理解有些牵强。这里,我只想说明一个道理,那就是:封装的对象的颗粒度尽量最小化。