1、 命令模式定义
命令模式主要解决将方法调用(Method invocation)封装起来。通过封装方法调用,我们可以把运算块包装成型。调用此运算的对象不需要关心事情是如何进行的,只需要知道如何使用包装成型的方法来完成指定任务即可。通过封装方法调用,可以做很多事情,如记录日志、重复使用这些封装来实现撤销(undo)。
2、要点
将发出请求的对象和执行请求的对象解耦
在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作
调用者通过调用命令对象的Execute发出请求,这会使得接收者的动作被调用
调用者可以接收命令作为参数,甚至在运行时动态的进行
命令可以支持撤销,做法是实现一个undo方法来回到execute方法执行之前的状态
宏命令是一种简单的延伸,允许调用多个命令。红方法也可以支持撤销
实际操作时,很常见使用聪明的命令对象,也就是在命令内部直接实现了命令请求而不去调用接受者的实现
命令也可以用来实现日志和事务系统
命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式支持可撤销操作
3、例子代码
作为例子,本文实现家电自动化的API作为练习
背景:现在提供一个带有七对控制开闭的按钮和一个公用的撤销按钮,要求编程实现对按钮对相应的家电的开关控制,同时支持撤销按钮对最后一个按下的按钮的撤销,
最主要的是,要支持将来的扩展
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommandPattern
{
/// <summary>
/// 定义命令接口
/// </summary>
public interface ICommand
{
bool Execute();
bool Undo();
}
/// <summary>
/// 什么也不做的命令
/// </summary>
public class NoCommand : ICommand
{
public bool Execute()
{
Console.WriteLine("Do Nothing!");
return true;
}
public bool Undo()
{
Console.WriteLine("Do Nothing!");
return true;
}
}
/// <summary>
/// 原始点灯类
/// </summary>
public class Light
{
public void on()
{
Console.WriteLine("Light_ON");
}
public void off()
{
Console.WriteLine("Light_OFF");
}
}
/// <summary>
/// 点灯打开命令具体实现
/// </summary>
public class LightOnCommand : ICommand
{
private Light m_Receiver;
public LightOnCommand(Light pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.on();
return true;
}
public bool Undo()
{
m_Receiver.off();
return true;
}
#endregion
}
/// <summary>
/// 点灯关闭命令具体实现
/// </summary>
public class LightOffCommand : ICommand
{
private Light m_Receiver;
public LightOffCommand(Light pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.off();
return true;
}
public bool Undo()
{
m_Receiver.on();
return true;
}
#endregion
}
/// <summary>
/// 户外点灯类
/// </summary>
public class OutDoorLight
{
public void on()
{
Console.WriteLine("OutDoorLight_ON");
}
public void off()
{
Console.WriteLine("OutDoorLight_OFF");
}
}
/// <summary>
/// 户外点灯打开命令
/// </summary>
public class OutDoorLightOnCommand : ICommand
{
private OutDoorLight m_Receiver;
public OutDoorLightOnCommand(OutDoorLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.on();
return true;
}
public bool Undo()
{
m_Receiver.off();
return true;
}
#endregion
}
/// <summary>
/// 户外点灯关闭命令
/// </summary>
public class OutDoorLightOffCommand : ICommand
{
private OutDoorLight m_Receiver;
public OutDoorLightOffCommand(OutDoorLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.off();
return true;
}
public bool Undo()
{
m_Receiver.on();
return true;
}
#endregion
}
/// <summary>
/// 屋顶电灯
/// </summary>
public class CellingLight
{
public void on()
{
Console.WriteLine("CellingLight_ON");
}
public void off()
{
Console.WriteLine("CellingLight_OFF");
}
public void dim()
{
Console.WriteLine("CellingLight_DIM");
}
}
/// <summary>
/// 屋顶电灯打开命令
/// </summary>
public class CellingLightOnCommand : ICommand
{
private CellingLight m_Receiver;
public CellingLightOnCommand(CellingLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.on();
return true;
}
public bool Undo()
{
m_Receiver.off();
return true;
}
#endregion
}
/// <summary>
/// 屋顶电灯关闭命令
/// </summary>
public class CellingLightOffCommand : ICommand
{
private CellingLight m_Receiver;
public CellingLightOffCommand(CellingLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.off();
return true;
}
public bool Undo()
{
m_Receiver.on();
return true;
}
#endregion
}
/// <summary>
/// 电视机
/// </summary>
public class TV
{
public void on()
{
Console.WriteLine("TV_ON");
}
public void off()
{
Console.WriteLine("TV_OFF");
}
public void setInputChannel(int index)
{
Console.WriteLine("TV_InputChannel_" + index.ToString());
}
public void setVolume(int volume)
{
Console.WriteLine("TV_Volume_" + volume.ToString());
}
}
/// <summary>
/// 电视机打开命令
/// </summary>
public class TVOnCommand : ICommand
{
private TV m_Receiver;
public TVOnCommand(TV pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.on();
return true;
}
public bool Undo()
{
m_Receiver.off();
return true;
}
#endregion
}
/// <summary>
/// 电视机关闭命令
/// </summary>
public class TVOffCommand : ICommand
{
private TV m_Receiver;
public TVOffCommand(TV pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.off();
return true;
}
public bool Undo()
{
m_Receiver.on();
return true;
}
#endregion
}
/// <summary>
/// 花园灯
/// </summary>
public class GardenLight
{
public void setDustTime(string time)
{
Console.WriteLine("GardenLight_" + time);
}
public void setDownTime(string time)
{
Console.WriteLine("GardenLight_" + time);
}
public void manualOn()
{
Console.WriteLine("GardenLight_ON");
}
public void manualOff()
{
Console.WriteLine("GardenLight_OFF");
}
}
/// <summary>
/// 花园灯打开命令
/// </summary>
public class GardenLightOnCommand : ICommand
{
private GardenLight m_Receiver;
public GardenLightOnCommand(GardenLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.manualOn();
return true;
}
public bool Undo()
{
m_Receiver.manualOff();
return true;
}
#endregion
}
/// <summary>
/// 花园灯关闭命令
/// </summary>
public class GardenLightOffCommand : ICommand
{
private GardenLight m_Receiver;
public GardenLightOffCommand(GardenLight pLight)
{
m_Receiver = pLight;
}
#region ICommand 成员
public bool Execute()
{
m_Receiver.manualOff();
return true;
}
public bool Undo()
{
m_Receiver.manualOn();
return true;
}
#endregion
}
/// <summary>
/// 屋顶吊扇
/// </summary>
public class CeilingFan
{
private int m_speed;
public CeilingFan()
{
m_speed = 0;
}
public void high()
{
m_speed = 100;
Console.WriteLine("CeilingFan_High");
}
public void low()
{
m_speed = 10;
Console.WriteLine("CeilingFan_Low");
}
public void off()
{
m_speed = 0;
Console.WriteLine("CeilingFan_Off");
}
public int getSpeed()
{
//Console.WriteLine("CeilingFan_Speed");
return m_speed;
}
}
/// <summary>
/// 屋顶吊扇打开命令
/// </summary>
public class CeilingFanOnCommand : ICommand
{
private CeilingFan m_Receiver;
private int m_PreSpeed;
public CeilingFanOnCommand(CeilingFan pLight)
{
m_Receiver = pLight;
m_PreSpeed = 0;
}
#region ICommand 成员
public bool Execute()
{
m_PreSpeed = m_Receiver.getSpeed();
m_Receiver.low();
return true;
}
public bool Undo()
{
m_PreSpeed = m_Receiver.getSpeed();
if (m_PreSpeed == 100)
{
m_Receiver.high();
}
else if (m_PreSpeed == 10)
{
m_Receiver.low();
}
else
{
m_Receiver.off();
}
return true;
}
#endregion
}
/// <summary>
/// 屋顶吊扇关闭命令
/// </summary>
public class CeilingFanOffCommand : ICommand
{
private CeilingFan m_Receiver;
private int m_PreSpeed;
public CeilingFanOffCommand(CeilingFan pLight)
{
m_Receiver = pLight;
m_PreSpeed = 0;
}
#region ICommand 成员
public bool Execute()
{
m_PreSpeed = m_Receiver.getSpeed();
m_Receiver.off();
return true;
}
public bool Undo()
{
m_PreSpeed = m_Receiver.getSpeed();
if (m_PreSpeed == 100)
{
m_Receiver.high();
}
else if (m_PreSpeed == 10)
{
m_Receiver.low();
}
else
{
m_Receiver.off();
}
return true;
}
#endregion
}
/// <summary>
/// 宏命令
/// </summary>
public class MicroCommand : ICommand
{
private ICommand[] m_subCommands;
public MicroCommand(ICommand[] subCommands)
{
m_subCommands = subCommands;
}
#region ICommand 成员
public bool Execute()
{
for (int i = 0; i < m_subCommands.Length;i++ )
{
m_subCommands[i].Execute();
}
return true;
}
public bool Undo()
{
for (int i = m_subCommands.Length -1 ; i >=0 ; i--)
{
m_subCommands[i].Undo();
}
return true;
}
#endregion
}
/// <summary>
/// 遥控器命令触发类
/// </summary>
public class RemoteControl
{
private ICommand[] m_OnCommands;
private ICommand[] m_OffCommands;
private ICommand m_CurrentCommand;
public RemoteControl()
{
m_OnCommands = new ICommand[7];
m_OffCommands = new ICommand[7];
for (int i = 0; i < m_OnCommands.Length;i++ )
{
m_OnCommands[i] = new NoCommand();
m_OffCommands[i] = new NoCommand();
}
m_CurrentCommand = new NoCommand();
}
/// <summary>
///存储命令
/// </summary>
/// <param name="index"></param>
/// <param name="onCommand"></param>
/// <param name="offCommand"></param>
public void SetCommand(int index,ICommand onCommand,ICommand offCommand)
{
m_OnCommands[index] = onCommand;
m_OffCommands[index] = offCommand;
}
/// <summary>
/// 触发打开命令
/// </summary>
/// <param name="index"></param>
public void OnButtonWasPushed(int index)
{
m_OnCommands[index].Execute();
m_CurrentCommand = m_OnCommands[index];
}
/// <summary>
/// 触发关闭命令
/// </summary>
/// <param name="index"></param>
public void OffButtonWasPushed(int index)
{
m_OffCommands[index].Execute();
m_CurrentCommand = m_OffCommands[index];
}
public void Undo()
{
m_CurrentCommand.Undo();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommandPattern
{
class Program
{
static void Main(string[] args)
{
RemoteControl pRemoteControl = new RemoteControl();
Light pLight = new Light();
ICommand pLightOnCommand = new LightOnCommand(pLight);
ICommand pLightOffCommand = new LightOffCommand(pLight);
//pRemoteControl.SetCommand(0, pLightOnCommand, pLightOffCommand);
OutDoorLight pOutDoorLight = new OutDoorLight();
ICommand pOutDoorLightOnCommand = new OutDoorLightOnCommand(pOutDoorLight);
ICommand pOutDoorLightOffCommand = new OutDoorLightOffCommand(pOutDoorLight);
//pRemoteControl.SetCommand(1, pOutDoorLightOnCommand, pOutDoorLightOffCommand);
CellingLight pCellingLight = new CellingLight();
ICommand pCellingLightOnCommand = new CellingLightOnCommand(pCellingLight);
ICommand pCellingLightOffCommand = new CellingLightOffCommand(pCellingLight);
//pRemoteControl.SetCommand(2, pCellingLightOnCommand, pCellingLightOffCommand);
TV pTV = new TV();
ICommand pTVOnCommand = new TVOnCommand(pTV);
ICommand pTVOffCommand = new TVOffCommand(pTV);
//pRemoteControl.SetCommand(3, pTVOnCommand, pTVOffCommand);
GardenLight pGardenLight = new GardenLight();
ICommand pGardenLightOnCommand = new GardenLightOnCommand(pGardenLight);
ICommand pGardenLightOffCommand = new GardenLightOffCommand(pGardenLight);
//pRemoteControl.SetCommand(4, pGardenLightOnCommand, pGardenLightOffCommand);
CeilingFan pCeilingFan = new CeilingFan();
ICommand pCeilingFanOnCommand = new CeilingFanOnCommand(pCeilingFan);
ICommand pCeilingFanOffCommand = new CeilingFanOffCommand(pCeilingFan);
//pRemoteControl.SetCommand(5, pCeilingFanOnCommand, pCeilingFanOffCommand);
MicroCommand pPartOnCommand = new MicroCommand(new ICommand[] {
pLightOnCommand,
pOutDoorLightOnCommand,
pCellingLightOnCommand,
pTVOnCommand,
pGardenLightOnCommand,
pCeilingFanOnCommand});
MicroCommand pPartOffCommand = new MicroCommand(new ICommand[] {
pLightOffCommand,
pOutDoorLightOffCommand,
pCellingLightOffCommand,
pTVOffCommand,
pGardenLightOffCommand,
pCeilingFanOffCommand});
pRemoteControl.SetCommand(0, pPartOnCommand, pPartOffCommand);
pRemoteControl.OnButtonWasPushed(0);
pRemoteControl.OffButtonWasPushed(0);
pRemoteControl.Undo();
}
}
}
4、基本类图