码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-07-28 18:38:09      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:设计模式   命令模式   

  命令(Command)模式:又称Action模式或者Transaction模式。它属于对象的行为模式。
  命令模式把一个请求或者操作封装到一个对象中,于是这些命令可以被:
  重复多次
  取消
  取消后又再重做

  命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开(解耦)。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。

  命令模式涉及到五个角色,分别为:
  客户(Client)角色:创建一个具体命令(ConcreteCommand)对象,并设置命令的接收者。
  命令(Command)角色:定义一个给所有命令类的抽象接口,定义了统一的 execute() 接口方法。
  具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现 Command 接口,并实现 execute() 方法,负责调用接收者的相应操作。
  请求者(Invoker)角色:负责调用由 Client 下达的对象执行请求。
  接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法为行动方法。

  这只是通用划分,实现时不一定有这些,设计模式只是思维构建的方式,没有一一对应的模板滴。

   技术分享

来看代码:

using System;
using System.Collections.Generic;

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

    /* The Invoker class */
    public class Switch
    {
        private List<ICommand> _commands = new List<ICommand>();

        public void StoreAndExecute(ICommand command)
        {
            _commands.Add(command);
            command.Execute();
        }
    }

    /* The Receiver class */
    public class Light
    {
        public void TurnOn()
        {
            Console.WriteLine("The light is on");
        }

        public void TurnOff()
        {
            Console.WriteLine("The light is off");
        }
    }

    /* The Command for turning on the light - ConcreteCommand #1 */
    public class FlipUpCommand : ICommand
    {
        private Light _light;

        public FlipUpCommand(Light light)
        {
            _light = light;
        }

        public void Execute()
        {
            _light.TurnOn();
        }
    }

    /* The Command for turning off the light - ConcreteCommand #2 */
    public class FlipDownCommand : ICommand
    {
        private Light _light;

        public FlipDownCommand(Light light)
        {
            _light = light;
        }

        public void Execute()
        {
            _light.TurnOff();
        }
    }

    /* The test class or client */
    internal class Program
    {
        public static void Main(string[] args)
        {
            Light lamp = new Light();
            ICommand switchUp = new FlipUpCommand(lamp);
            ICommand switchDown = new FlipDownCommand(lamp);

            Switch s = new Switch();
            string arg = args.Length > 0 ? args[0].ToUpper() : null;
            if (arg == "ON")
            {
                s.StoreAndExecute(switchUp);
            }
            else if (arg == "OFF")
            {
                s.StoreAndExecute(switchDown);
            }
            else
            {
                Console.WriteLine("Argument \"ON\" or \"OFF\" is required.");
            }
        }
    }
}

【注意】:在某些简单业务场景下,可在 ConcreteCommand 类的 execute 方法中直接编写实现代码,而省去接收者(Receiver)类以简化代码。如在本应用场景中省去 Receiver 类的创建。

来看一个实际例子:
  在射击游戏中,用户可以自定义快捷键,根据使用习惯来设置快捷键,如“W”键可以设置为“开枪”的快捷键,也可以设置为“前进”的快捷键,可通过命令模式来实现快捷键设置,类图如图5所示:

   技术分享

  在图中,ShortcutKey充当请求调用者,在其press()方法中将判断用户按的是哪个按键,再调用命令对象的execute()方法,在具体命令对象的execute()方法中将调用接收者如ShotHandler、GoAheadHandler的action()方法来执行具体操作。在实现时可以将具体命令类类名和键盘按键的键码(Keycode)存储在配置文件中,配置文件格式如下所示:

……  

<FunctionMapping keycode="87" commandClass="ShotCommand"/>  

<FunctionMapping keycode="38" commandClass="GoAheadCommand"/>  

……  

  如果需要更换快捷键,只需修改键码和具体命令类的映射关系即可;如果需要在游戏的升级版本中增加一个新功能,只需增加一个新的具体命令类,可通过修改配置文件来为其设置对应的按键,原有类库代码无需任何修改,很好地符合开闭原则。

  适用性:在软件系统中,行为请求者与行为实现者之间通常呈现一种紧耦合的关系。但在某些场合,比如要对行为进行记录撤销重做事务等处理,这种无法抵御变化的紧耦合是不合适的。这种情况下,使用 command 模式将行为请求者与行为实现者进行解耦。

  一个典型的应用场景就是处理命令队列,减少行为请求者和动作执行者的耦合,提高灵活性和降低代码冗余。

  另外,对于撤销事务,有两种实现方式:
  1) 在execute()方法执行前先存储当前状态,当undo()方法调用时,将当前状态转换为之前存储的状态(简单,保存了完整信息,浪费空间,没必要)。
  2) 只保存状态间变化的信息,当execute()或undo()调用时只改变这些存储的信息

参考:
https://zh.wikipedia.org/wiki/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F
http://www.ibm.com/developerworks/cn/java/design/
http://treelib.com/book-detail-id-59-aid-3471.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:设计模式   命令模式   

原文地址:http://blog.csdn.net/kzq_qmi/article/details/47108307

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!