一、定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作.
我觉得可以这样:将一个请求封装为一个对象,对请求排队或记录请求日志,以及支持可撤销的操作;从而使你可用不同的请求对客户进行参数化;
二、实例:一个遥控面板,两台小家电。一个面板控制两台小家电
2.1 不用命令模式实现
命令发起者:一块遥控器
命令接收者:一堆小家电
小家电接口:
public interface ISmallAppliance { int Appid { get; set; } void Open(); void Off(); }
电器:
public class Purifier : ISmallAppliance { public int Appid { get; set; } public Purifier(int appid) { Appid = appid; Console.WriteLine("净化器: {0}", Appid); } public void Open() { Console.Write(" 启动【净化器】成功."); } public void Off() { Console.Write(" 关闭【净化器】成功."); } } public class Kettle : ISmallAppliance { public int Appid { get; set; } public Kettle(int appid) { Appid = appid; Console.WriteLine("电水壶: {0}", Appid); } public void Open() { Console.Write(" 启动【电水壶】成功."); } public void Off() { Console.Write(" 关闭【电水壶】成功."); } }
遥控面板:
public class CommandPannel { List<ISmallAppliance> apps = new List<ISmallAppliance>(); public void Sign(ISmallAppliance _sa) { if (!apps.Contains(_sa)) apps.Add(_sa); } public void OpenCommand(int appid) { ISmallAppliance app = apps.Where(q => q.Appid == appid).FirstOrDefault(); app.Open(); } public void OffCommand(int appid) { ISmallAppliance app = apps.Where(q => q.Appid == appid).FirstOrDefault(); app.Off(); } }
客户端:
//客厅一台电水壶 Command.ISmallAppliance kettle_1 = new Command.Kettle(1); //厨房一台电水壶 Command.ISmallAppliance kettle_2 = new Command.Kettle(2); //卧室一台净化器 Command.ISmallAppliance purifier_1 = new Command.Purifier(100); List<Command.ISmallAppliance> smallAppliances = new List<Command.ISmallAppliance>(); smallAppliances.Add(kettle_1); smallAppliances.Add(kettle_2); smallAppliances.Add(purifier_1); //遥控器 Command.CommandPannel cp = new Command.CommandPannel(smallAppliances); //打开:kettle_1 cp.OpenCommand(kettle_1.Appid); //关闭:purifier_1 cp.OffCommand(purifier_100.Appid);
由上可知:
命令的发出者—遥控面板 和 命令的接收者—注册的各个小家电.
命令发出者和命令接收者是紧耦合的:关闭和打开需要传递具体的电器ID。
---------------------------------------------------割----------------------------------------------------
2.2、命令模式实现
重温一下定义,其实每个设计模式的定义很重要,很多都限定了使用场景。
定义:将一个请求封装为一个对象,对请求排队或记录请求日志,以及支持可撤销的操作;从而使你可用不同的请求对客户进行参数化;
我们将定义分三个层次解读:
2.2.1 将一个请求封装为一个对象.
即:我们将命令抽象,单独拿出来封装为对象。
也就是 命令模式 三大要素之一: Command (命令载体)
原来:遥控器有开按钮和关闭按钮。
public class CommandPannel { List<ISmallAppliance> apps = new List<ISmallAppliance>(); public void Sign(ISmallAppliance _sa) { if (!apps.Contains(_sa)) apps.Add(_sa); } public void OpenCommand(int appid) { ISmallAppliance app = apps.Where(q => q.Appid == appid).FirstOrDefault(); app.Open(); } public void OffCommand(int appid) { ISmallAppliance app = apps.Where(q => q.Appid == appid).FirstOrDefault(); app.Off(); } }
现在:我们需要进行抽象,将命令抽象出来,像这样 :当然每个命令指定了执行者 protected SmallAppliance sa;这个合乎实际,每个命令肯定针对具体的电器。
abstract public class Commands { protected SmallAppliance sa; public Commands(SmallAppliance _sa) { sa = _sa; } abstract public void Do(); } public class OpenCommand : Commands { public OpenCommand(SmallAppliance _sa) : base(_sa) { } override public void Do() { sa.Open(); } } public class OffCommand : Commands { public OffCommand(SmallAppliance _sa) : base(_sa) { } override public void Do() { sa.Off(); } }
2.2.2 对请求排队或记录请求日志,以及支持可撤销的操作
这是说的谁?遥控器 — 命令模式 三大要素之一:Invoker(请求处理者)
不过现在的遥控器,要拥有下面三个功能:请求排队、记录日志、可撤销
public class Pannel { List<Commands> cmds = new List<Commands>(); public Pannel() { Console.WriteLine("遥控器."); } public void Send(Commands cmd) { //请求排队 cmds.Add(cmd); //记录日志 Console.WriteLine("发送命令时间 : {0}", DateTime.Now); } public void CancleCmd(Commands cmd) { //可撤销 cmds.Remove(cmd); //记录日志 Console.WriteLine("取消命令时间 : {0}", DateTime.Now); } public void Execute() { if (cmds != null && cmds.Count > 0) { foreach (var cmd in cmds) { cmd.Do(); } } } }
这就是我们改造之后的遥控器,简单粗暴的直接执行命令,不管谁的。来者不拒。
2.2.3 命令模式 三大要素之一:Receiver(接收者)
abstract public class SmallAppliance { abstract public int ID { get; set; } abstract public void Open(); abstract public void Off(); } public class Purifier : SmallAppliance { public Purifier(int id) { ID = id; Console.WriteLine("净化器: {0}", ID); } override public int ID { get; set; } override public void Open() { Console.Write(" 启动【净化器{0}】成功.", ID); } override public void Off() { Console.Write(" 关闭【净化器{0}】成功.", ID); } } public class Kettle : SmallAppliance { public Kettle(int id) { ID = id; Console.WriteLine("电水壶: {0}", ID); } override public int ID { get; set; } override public void Open() { Console.Write(" 启动【电水壶{0}】成功.", ID); } override public void Off() { Console.Write(" 关闭【电水壶{0}】成功.", ID); } }
2.2.4 从而使你可用不同的请求对客户进行参数化
看看原来的客户端:打开和关闭没有好的办法进行统一传递参数,需要传递具体的电器的具体ID号
//客厅一台电水壶 Command.ISmallAppliance kettle_1 = new Command.Kettle(1); //厨房一台电水壶 Command.ISmallAppliance kettle_2 = new Command.Kettle(2); //卧室一台净化器 Command.ISmallAppliance purifier_1 = new Command.Purifier(100); List<Command.ISmallAppliance> smallAppliances = new List<Command.ISmallAppliance>(); smallAppliances.Add(kettle_1); smallAppliances.Add(kettle_2); smallAppliances.Add(purifier_1); //遥控器 Command.CommandPannel cp = new Command.CommandPannel(smallAppliances); //打开:kettle_1 cp.OpenCommand(kettle_1.Appid); //关闭:purifier_1 cp.OffCommand(purifier_100.Appid);
再来看看现在:
//Receiver(接收者):客厅一台电水壶 Command.SmallAppliance kettle_1 = new Command.Kettle(1); //Receiver(接收者):厨房一台电水壶 Command.SmallAppliance kettle_2 = new Command.Kettle(2); //Receiver(接收者):卧室一台净化器 Command.SmallAppliance purifier_100 = new Command.Purifier(100); //Invoker(处理者)—遥控器 Command.Pannel cp = new Command.Pannel(); Command.OpenCommand cmd_open_k1 = new Command.OpenCommand(kettle_1); Command.OpenCommand cmd_open_p100 = new Command.OpenCommand(kettle_1); Command.OffCommand cmd_off_k1 = new Command.OffCommand(kettle_1); Command.OffCommand cmd_off_p100 = new Command.OffCommand(kettle_1); //发送命令 cp.Send(cmd_open_k1); cp.Send(cmd_open_p100); cp.Send(cmd_off_k1); cp.CancleCmd(cmd_off_k1); cp.Send(cmd_off_p100); //执行命令 cp.Execute();
三、总结
1、Recevier(接收者):最简单的接收者还是那些小家电,还是一样的味道.
2、Command(抽象命令): 将遥控器的的命令或者请求,抽象为Command(命令).【这是思想重要的转变】
3、Invoker(处理者):然后改造遥控器使之拥有三个核心功能:请求排队、记录日志、可撤销.【操作核心】
4、Client(客户端):就是我,我家里买了两台电水壶外加一台净化器,然后我快速的按着遥控器,嘀嘀,嘀嘀,嘀嘀,嘀嘀,嘀,TMD错了,撤销~~。然后喝水吃饭打豆豆