博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式(五):命令模式
阅读量:4650 次
发布时间:2019-06-09

本文共 8003 字,大约阅读时间需要 26 分钟。

 

一、定义

 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作.

我觉得可以这样:将一个请求封装为一个对象,对请求排队或记录请求日志,以及支持可撤销的操作;从而使你可用不同的请求对客户进行参数化;

二、实例:一个遥控面板,两台小家电。一个面板控制两台小家电

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
apps = new List
(); 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
smallAppliances = new List
(); 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
apps = new List
(); 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
cmds = new List
(); 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
smallAppliances = new List
(); 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错了,撤销~~。然后喝水吃饭打豆豆

转载于:https://www.cnblogs.com/sunchong/p/5106513.html

你可能感兴趣的文章
使用java中replaceAll方法替换字符串中的反斜杠
查看>>
Some configure
查看>>
流量调整和限流技术 【转载】
查看>>
1 线性空间
查看>>
VS不显示最近打开的项目
查看>>
DP(动态规划)
查看>>
chkconfig
查看>>
2.抽取代码(BaseActivity)
查看>>
夏天过去了, 姥爷推荐几套来自smashingmagzine的超棒秋天主题壁纸
查看>>
反射的所有api
查看>>
css 定位及遮罩层小技巧
查看>>
[2017.02.23] Java8 函数式编程
查看>>
sprintf 和strcpy 的差别
查看>>
JS中window.event事件使用详解
查看>>
ES6深入学习记录(一)class方法相关
查看>>
C语言对mysql数据库的操作
查看>>
INNO SETUP 获得命令行参数
查看>>
HTML5与CSS3权威指南之CSS3学习记录
查看>>
docker安装部署
查看>>
AVL树、splay树(伸展树)和红黑树比较
查看>>