快捷搜索:
来自 计算机编程 2019-11-05 03:41 的文章
当前位置: 67677新澳门手机版 > 计算机编程 > 正文

实现命令设计模式,读书笔记07

本文的定义内容来自浅显设计情势一书.

07 《Head First设计格局》 读书笔记07 封装调用:命令情势

项目供给

图片 1

有那样四个可编制程序的流行遥控器, 它有7个可编制程序插槽, 每一种插槽可连续几日来不一致的家电设备. 各个插槽对应七个按键: 开, 关(ON, OFF). 别的还会有三个大局的吊销按键(UNDO).

现在客户想利用那几个遥控器来决定不相同商家的家用电器, 举例电灯, 太阳热辐射能热水器, 电扇, 音响等等.

客商提出让自己编写多个接口, 能够让那几个遥控器调节插在插槽上的一个或风流浪漫组织设立备.

看一下脚下各家厂家都有啥样家用电器:

图片 2

难题来了, 那一个家用电器并未联手的标准....大约各自都有谈得来的风华正茂套调整方法.. 况兼其后还要加上很三种家电.

 

规划思路

那就要求思谋一下技术方案了:

率先要思虑暌违关怀点(Separation of concerns),  遥控器应该可以解释按键动作并得以发送诉求, 然则它不应该驾驭家电和怎么着按钮家电等.

唯独当前遥控器只可以做按钮效率, 那么怎么让它去决定电灯只怕音响呢? 我们不想让遥控器知道这么些实际的家用电器, 更不想写出上面包车型大巴代码:

if slot1 == Light then Light.On()
else if slot1 == Hub....

提及那就只可以涉及命令格局(Command Pattern)了.

一声令下形式允许你把动作的须要者和动作的骨子里试行者解耦. 这里, 动作的诉求者正是遥控器, 而推行动作的指标正是有个别家电.

那是怎么解耦的呢? 怎么只怕实现啊?

那就要求引入"命令对象(command object)"了. 命令对象会封装在某些对象上(举个例子次卧的灯)施行某些动作的伸手(举例开灯). 所以, 假使大家为每一个按键都准备贰个下令对象, 那么当开关被按下的时候, 我们就能够调用那些命令对象去实施某些动作. 遥控器自身并不知器具体施行的动作是什么样, 它只是有一个限令对象, 那些命令对象领悟去对如何电器去做哪些的操作. 就这么, 遥控器和电灯解耦了.

难点引进

  有三个沾满多组按钮开关的遥控器,带有可编制程序插槽,每一种都得以内定到二个比不上的小家用电器装置;有大多厂家开拓的各样家电装置调整类;希望创立生机勃勃组API,让各类插槽调节贰个或风度翩翩组设置。

  思考:不应当让遥控器知道太多厂家类的细节,否则越多的小家用电器加进去,就必须修正代码。

三个限令格局的实际上例子

三个快餐厅:

图片 3

客商给推销员订单, 前台经理把订单放到柜台并说: "有新订单了", 然后大厨遵照订单计划饭菜.

让我们紧凑剖判一下它们是怎么人机联作的:

图片 4

顾客来了, 说笔者想要杜塞尔多夫, 奶酪....正是成立了二个订单 (createOrder()).

订单上面写着顾客想要的饭菜. 

服务生得到订单 takeOrder(), 把订单得到柜台喊道: "有新订单了" (调用orderUp())

大师傅依据订单的提醒把饭菜做好 (orderUp()里面的动作). 

 

浅析一下以此例子的剧中人物和天职:

  • 订单里封装了做饭菜的须要. 可以把订单想象成叁个对象, 那几个指标就像对起火这些动作的须要. 并且它能够来回传递. 订单完毕了五个独有orderUp()方法的接口, 那个办法里面封装了做饭的操作流程. 订单何况对动作实践者的引用(厨神). 因为都打包了, 所以服务生不精晓订单里面有甚也不清楚厨神是何人. 店小二只传递订单, 并调用orderUp().
  • 故此, 服务生的职业就是传递订单同一时间调用orderUp(). 前台经理的取订单takeOrder()方法会传进来不相同的参数(区别客商的不等订单), 不过那正常, 因为她了然全数的订单都协助orderUp()方法.
  • 厨神知道怎么把饭做好. 后生可畏旦服务员调用了orderUp(), 大厨就接管了全方位职业把饭菜做好. 不过服务生和大厨是解耦的: 看板娘只有订单, 订单里封装着饭菜, 推销员只是调用订单上的二个艺术而已. 相像的, 厨神只是从订单上收到指令, 他没有和前台经理生机勃勃直接触.

 

项目设计图

回去大家的须要, 仿效快餐店的事例, 使用命令格局做一下安插:

图片 5

顾客Client创立了三个下令(Command)对象. 也等于外人拿起了多少个订单(点菜)计划上马点菜, 作者在切磋遥控器的槽要求插哪些家用电器. 命令对象和选择者是绑定在一同的. 相当于菜单和厨子, 遥控器的插槽和指标家电.

命令对象唯有一个方法execute(), 里面封装了调用采用者实际决定操作的动作. 约等于旅社订单的orderUp().

客商调用setCommand()方法. 约等于客户想好点什么菜了, 就写在订单上面了. 小编也想好遥控器要调节什么家用电器了, 列好项目清单了. 

调用者拿着早已setCommand的命令对象, 在以后有些时间点调用命令对象方面的execute()方法. 约等于推销员拿起订单走到柜台前, 大喊一声: "有订单来了, 起先做菜吧". 约等于本身把遥控器和器具的接口连接上了, 寻思上马调控.

终极选取者实施动作. 也便是厨师做饭. 家电使用自身独有的操纵措施进行动作.

这里面:

客商 --- 酒店客人, 我

命令 --- 订单, 插槽

调用者 --- 服务员, 遥控器

setCommand()设置命令 --- takeOrder() 取订单, 插上急需调节的电器

execute() 实践 ---  orderUp() 告诉柜台做饭, 按按键

接收者 --- 厨师, 家电

消灭净尽方案

  使用命令方式,将动作的伏乞者从动作的实施者对象中解耦。

  在该难题中,须要者能够是遥控器,而奉行者对象正是厂家类当中之少年老成的实例。

  利用“指令对象”,把诉求封装成三个特定对象,每一种按键都存款和储蓄多个发令对象,当按键被按下的时候,就能够请命令对象做相关的劳作。

  遥控器并没有供给知道事行业内部容是何等,只要有个指令对象能和不易的目的关联,把职业办好就足以了。

代码实行

全数命令对象急需落到实处的接口:

namespace CommandPattern.Abstractions
{
    public interface ICommand
    {
        void Execute();
    }
}

一盏灯:

using System;

namespace CommandPattern.Devices
{
    public class Light
    {
        public void On()
        {
            Console.WriteLine("Light is on");
        }

        public void Off()
        {
            Console.WriteLine("Light is off");
        }
    }
}

调控灯打开的下令:

using CommandPattern.Abstractions;
using CommandPattern.Devices;

namespace CommandPattern.Commands
{
    public class LightOnCommand : ICommand
    {
        private readonly Light light;

        public LightOnCommand(Light light)
        {
            this.light = light;
        }

        public void Execute()
        {
            this.light.On();
        }
    }
}

车库门: 

using System;

namespace CommandPattern.Devices
{
    public class GarageDoor
    {
        public void Up()
        {
            Console.WriteLine("GarageDoor is opened.");
        }

        public void Down()
        {
            Console.WriteLine("GarageDoor is closed.");
        }
    }
}

收起车库门命令:

using CommandPattern.Abstractions;
using CommandPattern.Devices;

namespace CommandPattern.Commands
{
    public class GarageDoorOpen : ICommand
    {
        private readonly GarageDoor garageDoor;

        public GarageDoorOpen(GarageDoor garageDoor)
        {
            this.garageDoor = garageDoor;
        }

        public void Execute()
        {
            garageDoor.Up();
        }
    }
}

粗略的遥控器:

using CommandPattern.Abstractions;

namespace CommandPattern.RemoteControls
{
    public class SimpleRemoteControl
    {
        public ICommand Slot { get; set; }
public void ButtonWasPressed()
        {
            Slot.Execute();
        }
    }
}

运转测量检验:

using System;
using CommandPattern.Commands;
using CommandPattern.Devices;
using CommandPattern.RemoteControls;

namespace CommandPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var remote = new SimpleRemoteControl();
            var light = new Light();
            var lightOn = new LightOnCommand(light);

            remote.Slot = lightOn;
            remote.ButtonWasPressed();

            var garageDoor = new GarageDoor();
            var garageDoorOpen = new GarageDoorOpenCommand(garageDoor);

            remote.Slot = garageDoorOpen;
            remote.ButtonWasPressed();
        }
    }
}

图片 6

 

命令情势定义

命令情势把伏乞封装成二个指标, 进而可以行使不一样的央求对别的对象进行参数化, 对央求排队, 记录恳求的野史, 并协助打消操作.

类图:

图片 7

效果图:

图片 8

用实例证实

  在饭店,客户将和睦的必要写在订单上,由推销员交给厨子,然后大厨遵照订单指令希图餐点。

全职能代码的实践

遥控器:

using System.Text;
using CommandPattern.Abstractions;
using CommandPattern.Commands;

namespace CommandPattern.RemoteControls
{
    public class RemoteControl
    {
        private ICommand[] onCommands;
        private ICommand[] offCommands;

        public RemoteControl()
        {
            onCommands = new ICommand[7];
            offCommands = new ICommand[7];

            var noCommand = new NoCommand();
            for (int i = 0; i < 7; i  )
            {
                onCommands[i] = noCommand;
                offCommands[i] = noCommand;
            }
        }

        public void SetCommand(int slot, ICommand onCommand, ICommand offCommand)
        {
            onCommands[slot] = onCommand;
            offCommands[slot] = offCommand;
        }

        public void OnButtonWasPressed(int slot)
        {
            onCommands[slot].Execute();
        }
        public void OffButtonWasPressed(int slot)
        {
            offCommands[slot].Execute();
        }

        public override string ToString()
        {
            var sb = new StringBuilder("n------------Remote Control-----------n");
            for(int i =0; i< onCommands.Length; i  ){
                sb.Append($"[slot{i}] {onCommands[i].GetType()}t{offCommands[i].GetType()} n");
            }
            return sb.ToString();
        }
    }
}

这之中有八个NoCommand, 它是三个空的类, 只是为着最初化command 以便以后不用判定是或不是为null.

关灯:

using CommandPattern.Abstractions;
using CommandPattern.Devices;

namespace CommandPattern.Commands
{
    public class LightOffCommand: ICommand
    {
        private readonly Light light;

        public LightOffCommand(Light light)
        {
            this.light = light;
        }

        public void Execute()
        {
            light.Off();
        }
    }
}

上面试三个略带挑衅性的, 音响:

namespace CommandPattern.Devices
{
    public class Stereo
    {
        public void On()
        {
            System.Console.WriteLine("Stereo is on.");
        }

        public void Off()
        {
            System.Console.WriteLine("Stereo is off.");
        }

        public void SetCD()
        {
            System.Console.WriteLine("Stereo is set for CD input.");
        }

        public void SetVolume(int volume)
        {
            System.Console.WriteLine($"Stereo's volume is set to {volume}");
        }
    }
}

声音展开命令:

using CommandPattern.Abstractions;

namespace CommandPattern.Devices
{
    public class StereoOnWithCDCommand : ICommand
    {
        private readonly Stereo stereo;

        public StereoOnWithCDCommand(Stereo stereo)
        {
            this.stereo = stereo;
        }

        public void Execute()
        {
            stereo.On();
            stereo.SetCD();
            stereo.SetVolume(10);
        }
    }
}

测量试验运转:

using System;
using CommandPattern.Commands;
using CommandPattern.Devices;
using CommandPattern.RemoteControls;

namespace CommandPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var remote = new RemoteControl();
            var light = new Light();
            var lightOn = new LightOnCommand(light);
            var lightOff = new LightOffCommand(light);
            var garageDoor = new GarageDoor();
            var garageDoorOpen = new GarageDoorOpenCommand(garageDoor);
            var garageDoorClose = new GarageDoorCloseCommand(garageDoor);
            var stereo = new Stereo();
            var stereoOnWithCD = new StereoOnWithCDCommand(stereo);
            var stereoOff = new StereoOffCommand(stereo);

            remote.SetCommand(0, lightOn, lightOff);
            remote.SetCommand(1, garageDoorOpen, garageDoorClose);
            remote.SetCommand(2, stereoOnWithCD, stereoOff);

            System.Console.WriteLine(remote);

            remote.OnButtonWasPressed(0);
            remote.OffButtonWasPressed(0);
            remote.OnButtonWasPressed(1);
            remote.OffButtonWasPressed(1);
            remote.OnButtonWasPressed(2);
            remote.OffButtonWasPressed(2);
        }
    }
}

图片 9

该要求的宏图图:

图片 10

还会有一个主题素材...废除按键呢?

 

本文由67677新澳门手机版发布于计算机编程,转载请注明出处:实现命令设计模式,读书笔记07

关键词: