Command设计模式-HeadFirst学习

1、 命令模式定义

命令模式主要解决将方法调用(Method invocation)封装起来。通过封装方法调用,我们可以把运算块包装成型。调用此运算的对象不需要关心事情是如何进行的,只需要知道如何使用包装成型的方法来完成指定任务即可。通过封装方法调用,可以做很多事情,如记录日志、重复使用这些封装来实现撤销(undo)。

2、要点

将发出请求的对象和执行请求的对象解耦

在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作

调用者通过调用命令对象的Execute发出请求,这会使得接收者的动作被调用

调用者可以接收命令作为参数,甚至在运行时动态的进行

命令可以支持撤销,做法是实现一个undo方法来回到execute方法执行之前的状态

宏命令是一种简单的延伸,允许调用多个命令。红方法也可以支持撤销

实际操作时,很常见使用聪明的命令对象,也就是在命令内部直接实现了命令请求而不去调用接受者的实现

命令也可以用来实现日志和事务系统

命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式支持可撤销操作

3、例子代码

作为例子,本文实现家电自动化的API作为练习
 背景:现在提供一个带有七对控制开闭的按钮和一个公用的撤销按钮,要求编程实现对按钮对相应的家电的开关控制,同时支持撤销按钮对最后一个按下的按钮的撤销,
 最主要的是,要支持将来的扩展

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommandPattern
{
    /// <summary>
    /// 定义命令接口
    /// </summary>
    public interface ICommand
    {
        bool Execute();

        bool Undo();
    }

    /// <summary>
    /// 什么也不做的命令
    /// </summary>
    public class NoCommand : ICommand
    {

        public bool Execute()
        {
            Console.WriteLine("Do Nothing!");
            return true;
        }

        public bool Undo()
        {
            Console.WriteLine("Do Nothing!");
            return true;
        }
    }

    /// <summary>
    /// 原始点灯类
    /// </summary>
    public class Light
    {
        public void on()
        {
            Console.WriteLine("Light_ON");
        }

        public void off()
        {
            Console.WriteLine("Light_OFF");
        }
    }

    /// <summary>
    /// 点灯打开命令具体实现
    /// </summary>
    public class LightOnCommand : ICommand
    {
        private Light m_Receiver;

        public LightOnCommand(Light pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.on();
            return true;
        }

        public bool Undo()
        {
            m_Receiver.off();
            return true;
        }

        #endregion
    }

    /// <summary>
    /// 点灯关闭命令具体实现
    /// </summary>
    public class LightOffCommand : ICommand
    {
        private Light m_Receiver;

        public LightOffCommand(Light pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.off();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.on();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 户外点灯类
    /// </summary>
    public class OutDoorLight
    {
        public void on()
        {
            Console.WriteLine("OutDoorLight_ON");
        }

        public void off()
        {
            Console.WriteLine("OutDoorLight_OFF");
        }
    }

    /// <summary>
    /// 户外点灯打开命令
    /// </summary>
    public class OutDoorLightOnCommand : ICommand
    {

         private OutDoorLight m_Receiver;

         public OutDoorLightOnCommand(OutDoorLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.on();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.off();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 户外点灯关闭命令
    /// </summary>
    public class OutDoorLightOffCommand : ICommand
    {

        private OutDoorLight m_Receiver;

        public OutDoorLightOffCommand(OutDoorLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.off();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.on();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 屋顶电灯
    /// </summary>
    public class CellingLight
    {
        public void on()
        {
            Console.WriteLine("CellingLight_ON");
        }

        public void off()
        {
            Console.WriteLine("CellingLight_OFF");
        }

        public void dim()
        {
            Console.WriteLine("CellingLight_DIM");
        }
    }

    /// <summary>
    /// 屋顶电灯打开命令
    /// </summary>
    public class CellingLightOnCommand : ICommand
    {

        private CellingLight m_Receiver;

        public CellingLightOnCommand(CellingLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.on();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.off();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 屋顶电灯关闭命令
    /// </summary>
    public class CellingLightOffCommand : ICommand
    {

        private CellingLight m_Receiver;

        public CellingLightOffCommand(CellingLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.off();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.on();
            return true;
        }
        #endregion
    }


    /// <summary>
    /// 电视机
    /// </summary>
    public class TV
    {
        public void on()
        {
            Console.WriteLine("TV_ON");
        }

        public void off()
        {
            Console.WriteLine("TV_OFF");
        }

        public void setInputChannel(int index)
        {
            Console.WriteLine("TV_InputChannel_" + index.ToString());
        }

        public void setVolume(int volume)
        {
            Console.WriteLine("TV_Volume_" + volume.ToString());
        }
    }

    /// <summary>
    /// 电视机打开命令
    /// </summary>
    public class TVOnCommand : ICommand
    {

        private TV m_Receiver;

        public TVOnCommand(TV pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.on();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.off();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 电视机关闭命令
    /// </summary>
    public class TVOffCommand : ICommand
    {

        private TV m_Receiver;

        public TVOffCommand(TV pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.off();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.on();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 花园灯
    /// </summary>
    public class GardenLight
    {
        public void setDustTime(string time)
        {
            Console.WriteLine("GardenLight_" + time);
        }

        public void setDownTime(string time)
        {
            Console.WriteLine("GardenLight_" + time);
        }

        public void manualOn()
        {
            Console.WriteLine("GardenLight_ON");
        }

        public void manualOff()
        {
            Console.WriteLine("GardenLight_OFF");
        }
    }

    /// <summary>
    /// 花园灯打开命令
    /// </summary>
    public class GardenLightOnCommand : ICommand
    {

        private GardenLight m_Receiver;

        public GardenLightOnCommand(GardenLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.manualOn();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.manualOff();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 花园灯关闭命令
    /// </summary>
    public class GardenLightOffCommand : ICommand
    {

        private GardenLight m_Receiver;

        public GardenLightOffCommand(GardenLight pLight)
        {
            m_Receiver = pLight;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_Receiver.manualOff();
            return true;
        }
        public bool Undo()
        {
            m_Receiver.manualOn();
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 屋顶吊扇
    /// </summary>
    public class CeilingFan
    {
        private int m_speed;

        public CeilingFan()
        {
            m_speed = 0;
        }
        
        public void high()
        {
            m_speed = 100;
            Console.WriteLine("CeilingFan_High");
        }

        public void low()
        {
            m_speed = 10; 
            Console.WriteLine("CeilingFan_Low");
        }

        public void off()
        {
            m_speed = 0;
            Console.WriteLine("CeilingFan_Off");
        }

        public int getSpeed()
        {
            //Console.WriteLine("CeilingFan_Speed");
            return m_speed;
        }
    }

    /// <summary>
    /// 屋顶吊扇打开命令
    /// </summary>
    public class CeilingFanOnCommand : ICommand
    {

        private CeilingFan m_Receiver;
        private int m_PreSpeed;

        public CeilingFanOnCommand(CeilingFan pLight)
        {
            m_Receiver = pLight;
            m_PreSpeed = 0;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_PreSpeed = m_Receiver.getSpeed();
            m_Receiver.low();
            return true;
        }
        public bool Undo()
        {
            m_PreSpeed = m_Receiver.getSpeed();
            if (m_PreSpeed == 100)
            {
                m_Receiver.high();
            }
            else if (m_PreSpeed == 10)
            {
                m_Receiver.low();
            }
            else
            {
                m_Receiver.off();
            }
            
            return true;
        }
        #endregion
    }

    /// <summary>
    /// 屋顶吊扇关闭命令
    /// </summary>
    public class CeilingFanOffCommand : ICommand
    {

        private CeilingFan m_Receiver;
        private int m_PreSpeed;

        public CeilingFanOffCommand(CeilingFan pLight)
        {
            m_Receiver = pLight;
            m_PreSpeed = 0;
        }

        #region ICommand 成员

        public bool Execute()
        {
            m_PreSpeed = m_Receiver.getSpeed();
            m_Receiver.off();
            return true;
        }
        public bool Undo()
        {
            m_PreSpeed = m_Receiver.getSpeed();
            if (m_PreSpeed == 100)
            {
                m_Receiver.high();
            }
            else if (m_PreSpeed == 10)
            {
                m_Receiver.low();
            }
            else
            {
                m_Receiver.off();
            }

            return true;
        }
        #endregion
    }

    /// <summary>
    /// 宏命令
    /// </summary>
    public class MicroCommand : ICommand
    {
        private ICommand[] m_subCommands;

        public MicroCommand(ICommand[] subCommands)
        {
            m_subCommands = subCommands;
        }

        #region ICommand 成员

        public bool Execute()
        {
            for (int i = 0; i < m_subCommands.Length;i++ )
            {
                m_subCommands[i].Execute();
            }
            return true;
        }

        public bool Undo()
        {
            for (int i = m_subCommands.Length -1 ; i >=0 ; i--)
            {
                m_subCommands[i].Undo();
            }
            return true;
        }

        #endregion
    }

    /// <summary>
    /// 遥控器命令触发类
    /// </summary>
    public class RemoteControl
    {
        private ICommand[] m_OnCommands;
        private ICommand[] m_OffCommands;
        private ICommand m_CurrentCommand;

        public RemoteControl()
        {
            m_OnCommands = new ICommand[7];
            m_OffCommands = new ICommand[7];

            for (int i = 0; i < m_OnCommands.Length;i++ )
            {
                m_OnCommands[i] = new NoCommand();
                m_OffCommands[i] = new NoCommand();
            }

            m_CurrentCommand = new NoCommand();
        }

        /// <summary>
        ///存储命令
        /// </summary>
        /// <param name="index"></param>
        /// <param name="onCommand"></param>
        /// <param name="offCommand"></param>
        public void SetCommand(int index,ICommand onCommand,ICommand offCommand)
        {
            m_OnCommands[index] = onCommand;
            m_OffCommands[index] = offCommand;
        }

        /// <summary>
        /// 触发打开命令
        /// </summary>
        /// <param name="index"></param>
        public void OnButtonWasPushed(int index)
        {
            m_OnCommands[index].Execute();
            m_CurrentCommand = m_OnCommands[index];
        }

        /// <summary>
        /// 触发关闭命令
        /// </summary>
        /// <param name="index"></param>
        public void OffButtonWasPushed(int index)
        {
            m_OffCommands[index].Execute();
            m_CurrentCommand = m_OffCommands[index];
        }

        public void Undo()
        {
            m_CurrentCommand.Undo();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommandPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            RemoteControl pRemoteControl = new RemoteControl();

            Light pLight = new Light();
            ICommand pLightOnCommand = new LightOnCommand(pLight);
            ICommand pLightOffCommand = new LightOffCommand(pLight);
            //pRemoteControl.SetCommand(0, pLightOnCommand, pLightOffCommand);

            OutDoorLight pOutDoorLight = new OutDoorLight();
            ICommand pOutDoorLightOnCommand = new OutDoorLightOnCommand(pOutDoorLight);
            ICommand pOutDoorLightOffCommand = new OutDoorLightOffCommand(pOutDoorLight);
            //pRemoteControl.SetCommand(1, pOutDoorLightOnCommand, pOutDoorLightOffCommand);

            CellingLight pCellingLight = new CellingLight();
            ICommand pCellingLightOnCommand = new CellingLightOnCommand(pCellingLight);
            ICommand pCellingLightOffCommand = new CellingLightOffCommand(pCellingLight);
            //pRemoteControl.SetCommand(2, pCellingLightOnCommand, pCellingLightOffCommand);

            TV pTV = new TV();
            ICommand pTVOnCommand = new TVOnCommand(pTV);
            ICommand pTVOffCommand = new TVOffCommand(pTV);
            //pRemoteControl.SetCommand(3, pTVOnCommand, pTVOffCommand);

            GardenLight pGardenLight = new GardenLight();
            ICommand pGardenLightOnCommand = new GardenLightOnCommand(pGardenLight);
            ICommand pGardenLightOffCommand = new GardenLightOffCommand(pGardenLight);
            //pRemoteControl.SetCommand(4, pGardenLightOnCommand, pGardenLightOffCommand);

            CeilingFan pCeilingFan = new CeilingFan();
            ICommand pCeilingFanOnCommand = new CeilingFanOnCommand(pCeilingFan);
            ICommand pCeilingFanOffCommand = new CeilingFanOffCommand(pCeilingFan);
            //pRemoteControl.SetCommand(5, pCeilingFanOnCommand, pCeilingFanOffCommand);

            MicroCommand pPartOnCommand = new MicroCommand(new ICommand[] { 
                pLightOnCommand,
                pOutDoorLightOnCommand, 
                pCellingLightOnCommand, 
                pTVOnCommand,
                pGardenLightOnCommand,
                pCeilingFanOnCommand});

            MicroCommand pPartOffCommand = new MicroCommand(new ICommand[] { 
                pLightOffCommand,
                pOutDoorLightOffCommand,
                pCellingLightOffCommand,
                pTVOffCommand,
                pGardenLightOffCommand,
                pCeilingFanOffCommand});

            pRemoteControl.SetCommand(0, pPartOnCommand, pPartOffCommand);

            pRemoteControl.OnButtonWasPushed(0);
            pRemoteControl.OffButtonWasPushed(0);


            pRemoteControl.Undo();
        }
    }
}

4、基本类图


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值