将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录日志,以及支持可撤销的操作。
在一些系统功能设计的时候,需要向某个对象发送请求,但是并不知道请求的接收者以及被请求的具体操作,而是在程序运行时指定具体的请求接收者。这段话比较抽象,下面通过一个实际生活中的例子来帮助大家理解。
假如我们设计了一款虚拟遥控器,用来控制智能家居电器的开关。在产品设计时我们并不知道每个按钮具体对应到哪样家居电器,而是根据用户选择,在软件运行时绑定具体的操作。这样一来,我们就需要在产品设计时将请求调用者(遥控器)与请求接受者(智能家居)解耦,使得调用者和接收者不直接交互。
结构说明 角色说明ICommand
命令接口,包含一个执行操作的方法。
ConcreteCommand
具体命令类,包含一个接收者对象,并调用接收者对象以实现Execute方法。
Receiver
接收者,知道如何执行一个操作以满足客户端传来的请求。
Invoker
调用者,要求该命令执行这个请求。
结构代码声明接收者Receiver,包含一个Action方法。
class Receiver { public void Action() { Console.WriteLine("called Receiver.Action()"); } }声明ICommand接口以及具体命令类ConcreteCommand,包含一个Receiver类型的成员。
interface ICommand { void Execute(); } class ConcreteCommand : ICommand { private Receiver _receiver; public ConcreteCommand(Receiver receiver) { _receiver = receiver; } public void Execute() { _receiver.Action(); } }声明调用者,提供SetCommand方法设置命令,并提供Call方法执行该命令。
class Invoker { private ICommand _command; public void SetCommand(ICommand command) { _command = command; } public void Call() { _command.Execute(); } }客户端调用:
class Program { static void Main(string[] args) { Receiver receiver = new Receiver(); ConcreteCommand concreteCommand = new ConcreteCommand(receiver); Invoker invoker = new Invoker(); invoker.SetCommand(concreteCommand); invoker.Call(); Console.ReadLine(); } }输出结果:
客户端创建一个ConcreteCommand对象并指定它的Reciever对象,再创建一个Invoker对象,存储该ConcreteCommand对象。Invoker通过ConcreteCommand的Execute方法提交请求,ConcreteCommand对象将请求传递给Receiver最终执行。
示例分析本节我们通过命令模式来实现虚拟遥控器的示例。首先创建两个Receiver:Light和TV,它们都提供各自打开/关闭的方法。
class Light { public void TurnOn() { Console.WriteLine("Light is turning on"); } public void TurnOff() { Console.WriteLine("Light is turning off"); } } class TV { public void TurnOn() { Console.WriteLine("TV is Turining on"); } public void TurnOff() { Console.WriteLine("TV is Turning off"); } }创建ICommand接口,并分别实现开灯、关灯、打开电视以及关闭电视四个命令。
interface ICommand { void Execute(); } class LightTurnOnCommand : ICommand { private Light _light; public LightTurnOnCommand(Light light) { _light = light; } public void Execute() { _light.TurnOn(); } } class LightTurnOffCommand : ICommand { private Light _light; public LightTurnOffCommand(Light light) { _light = light; } public void Execute() { _light.TurnOff(); } } class TVTurnOnCommand : ICommand { private TV _tv; public TVTurnOnCommand(TV tv) { _tv = tv; } public void Execute() { _tv.TurnOn(); } } class TVTurnOffCommand : ICommand { private TV _tv; public TVTurnOffCommand(TV tv) { _tv = tv; } public void Execute() { _tv.TurnOff(); } }创建遥控器RemoteController,包含一个命令集合,提供AddCommand方法向command集合添加命令。
class RemoteController { private List<ICommand> _commandList = new List<ICommand>(); public void AddCommand(ICommand command) { _commandList.Add(command); } public void Call(int i) { _commandList[i].Execute(); } }下面我们在客户端进行配置,首先创建一个remoteController遥控器,并绑定相应的操作,1->开灯,2->关灯,3->打开电视,4->关闭电视,99->退出遥控器。
class Program { static void Main(string[] args) { RemoteController remoteController = new RemoteController(); Light light = new Light(); LightTurnOnCommand lightTurnOn = new LightTurnOnCommand(light); LightTurnOffCommand lightTurnOff = new LightTurnOffCommand(light); TV tv = new TV(); TVTurnOnCommand tvTurnOn = new TVTurnOnCommand(tv); TVTurnOffCommand tvTurnOff = new TVTurnOffCommand(tv); remoteController.AddCommand(lightTurnOn); remoteController.AddCommand(lightTurnOff); remoteController.AddCommand(tvTurnOn); remoteController.AddCommand(tvTurnOff); int input = 0; do { Console.WriteLine("Please enter your command(enter 99 to exit):"); input = Convert.ToInt32(Console.ReadLine()); if (input == 99) { Console.WriteLine("Exit!"); break; } remoteController.Call(input - 1); } while (input != 99); Console.ReadLine(); } }