设计模式(五):命令模式

一、定义

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

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

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

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错了,撤销~~。然后喝水吃饭打豆豆

时间: 2024-10-16 21:57:28

设计模式(五):命令模式的相关文章

设计模式之命令模式20170719

行为型设计模式之命令模式: 一.含义 将请求(命令)封装成一个对象(内部有接收者对象,以及按照具体命令执行接收者操作的方法),传递给调用者,由调用者执行具体命令. 也就是把一个动作的执行分为执行对象(接收者角色).执行行为(命令角色),让两者相互独立而不相互影响,实现对动作解耦 二.代码说明 1.主要有三个角色 1)接收者角色 该角色就是干活的角色,被命令角色调用,其操作按具体命令的要求执行 2)命令角色 需要执行的所有命令都在这里声明,同时接收者所有的对象都在这里(接收者封装在这里,防止高层模

C#设计模式(15)——命令模式(Command Pattern)

原文:C#设计模式(15)--命令模式(Command Pattern) 一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的技术水平,因为对于一个功能的实现,高级工程师和初级工程师一样都会实现,但是区别在于它们实现功能的可扩展和可维护性,也就是代码的是否“优美”.可读.但是,要更好地应用,首先就必须了解各种设计模式和其应用场景,所以我还是希望继续完

设计模式之命令模式

命令模式的核心是把方法调用封装起来,调用的对象不需要关心是如何执行的. 定义:命令模式将"请求"封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也可以支持撤销操作. 先看一个例子,设计一个家电遥控器的API,可以通过遥控器发出命令来控制不同生产商生产的家电,比如关灯.开灯. 以下是一个简单的代码示例. 1 package cn.sp.test05; 2 /** 3 * 电灯类 4 * @author 2YSP 5 * 6 */ 7 public class Lig

跟我学设计模式视频教程——命令模式vs策略模式,唠嗑

课程视频 命令模式vs策略模式 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 跟我学设计模式视频教程--命令模式vs策略模式,唠嗑,布布扣,bubuko.com

用Java 8 Lambda表达式实现设计模式:命令模式

链接:http://www.importnew.com/16789.html 在这篇博客里,我将说明如何在使用Java 8 Lambda表达式的函数式编程方式时实现命令设计模式.命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化,并提供相应的操作.命令模式是一种通用编程方式,该方式基于运行时决策顺序来执行方法.模式的参与者如下: 命令 :声明用于执行操作的接口. 实体命令 :定义接收者对象和动作的绑定. 客户端 :创建实体命令实例并设置它的接收者. 调用者:

设计模式 ( 十三 ) 命令模式Command(对象行为型)

设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活. 例子1:电视机遥控器 : 遥控器是请求的发送者,电视机是请求的接收者,遥控器上有一些按钮如开,关,换频道等按钮就是具体命令,不同的按钮对应电视机的不同操作. 2.问题

设计模式(6)--命令模式

关键词 :空对象 有人称为设计模式 三层调用 1. 封装调用  , 把封装带到一个全新的境界: 把方法调用(method invocation) 封装起来. 2. 命令模式可将"动作的请求者" 从"动作的执行者" 对象中解耦. 3. 当需要将发出的请求和执行请求的对象解耦的时候,使用命令模式. OO原则: (1)封装变化 (2) 多用组合,少用继承 (3)针对接口编程,不针对实现编程 (4)为交互对象之间松耦合设计而努力 (5) 类应该对扩展开放,对修改关闭 (6)

设计模式 7 —— 命令模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 设计模式 7 —— 命令模式 概述 第1部分 问题引入 第2部分 定义和实现 第3部分 使用宏命令 第1部分 问题引入 首先看下,下面的要求: 实现命令接口 首先,让说有的命令对象实现相同的包含一个方法的接口. 1 /** 2 * 命令接口 3 * @ClassNam

每天一个设计模式之命令模式

作者按:<每天一个设计模式>旨在初步领会设计模式的精髓,目前采用javascript和python两种语言实现.诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :) 原文地址是:<每天一个设计模式之命令模式> 欢迎关注个人技术博客:godbmw.com.每周 1 篇原创技术分享!开源教程(webpack.设计模式).面试刷题(偏前端).知识整理(每周零碎),欢迎长期关注! 如果您也想进行知识整理 + 搭建功能完善/设计简约/快速启动的个人博客,请直接戳the

五分钟一个设计模式之命令模式

五分钟一个设计模式,用最简单的方法来描述设计模式. 小米智能模块的例子 前一段小米的老总雷军在印度的全英文演讲想必大家都还历历在目,不过今天我们讨论的主题不是那次演讲,而是小米智能模块.小米4发布时,雷军说,小米已经开发了一个智能模块,只要电器厂商将这个智能模块集成到自家的电器中,就可以用小米手机来控制它,并且小米智能模块才22块钱.是不是一件很牛X的事情?这个事情,从宏观上来看,通过小米手机来控制所有集成了智能模块的电器,就是使用了命令模式!下面我们来模拟一下这个事情. 首先,有一些家用电器的