美文网首页Unity Come On
Unity【话大】设计模式之命令模式

Unity【话大】设计模式之命令模式

作者: su9257_海澜 | 来源:发表于2018-12-24 01:10 被阅读131次

前言:笔者在最开始写程序的时候经常会遇到一种情况,例如更改一个字段、或者添加一种小功能,就要把原来写过的东西几乎废弃掉,或者更改大量以前写过的代码。又或者自己写的东西时间久了再去回顾,完全找不到到时为什么这么写的头绪,如果遇到了Bug更是无法快速定位在哪里小范围出现的问题。如果你也经常遇到这种问题,就说明你现阶段非常需要学习下设计模式了

在网上经常说的设计模式有23种,也有一些更多的设计模式,无非也是从这些设计模式中变种而来。如果让笔者来形容什么是设计模式,我认为设计模式是:一种思想,一种模式,一种套路,一种解决问题的高效策略



有说的不正确或者不准确的地方欢迎留言指正


有什么有趣的写作技巧或者想法欢迎大家给我留言,大家的帮助是我写下去最有效的动力



在日常生活中会遇到如下相关的操作,如果淘宝购物、外卖点单、购票时,我们会先把心仪的东西放入购物车,最后一起付款。又或者在外就餐时根据需求对原有餐单进行添加新的菜品或者对原有菜品进行撤销。

在开发中也会遇到如预设多个技能排序释放、接受事件到达一定数量时才执行的需求。

如果在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,将"行为请求者"与"行为实现者"解耦。将一组行为抽象为对象,可以实现二者之间的松耦合。这也是笔者今天要介绍的命令模式

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

下面我就以网上购物为例用命名模式实现

首先我们确定要买的东西时鼠标和键盘,剩下具体要买什么还没想好,但就是要买买买

    public interface IReceiver
    {
        void Buy();
    }
    public class ReceiverCherry : IReceiver
    {
        public void Buy()
        {
            this.Log("买了一个Cherry键盘");
        }
    }
    public class ReceiverLOGN : IReceiver
    {
        public void Buy()
        {
            this.Log("买了一个LOGN鼠标");
        }
    }

然后我们买任何东西这都是一个命令,但是这两样东西我们去淘宝还是京东买呢?那就一个地方买一个吧,这样就出现了两种命令

    public abstract class Command
    {
        protected IReceiver receiver = null;

        public Command(IReceiver receiver)
        {
            this.receiver = receiver;
        }
        public abstract void Execute();
    }

    public class TaoBaoCommad : Command
    {
        public TaoBaoCommad(IReceiver receiver) : base(receiver)
        {
        }

        public override void Execute()
        {
            this.Log("淘宝");
            receiver.Buy();
        }
    }

    public class JDCommand : Command
    {
        public JDCommand(IReceiver receiver) : base(receiver)
        {
        }

        public override void Execute()
        {
            this.Log("京东");
            receiver.Buy();
        }
    }

最后我们执行下要买的东西

    public class Invoker
    {
        public List<Command> commadGroup = new List<Command>();

        public void Execute()
        {
            foreach (var commad in commadGroup)
            {
                commad.Execute();
            }
        }
    }

这样,我们完整的一套命令模式就完成了。

解析

  • IReceiver的实现,包含行为的具体如何实施与执行。
  • Command可以理解为一个容器,用这个容器把具体的实施Receiver包裹在里面。在执行Execute时可以打印一个日志等先关操作
  • Invoker负责拆开包裹(command)来执行里面具体的Receiver

让我看看在PureMVC中,这种类似命令模式的实现,把一个要执行的事包裹起来,在需要的时候拆开包裹进行调用其中的内容

        /// <summary>
        /// 执行消息 通过反射找到需要执行handleNotification所属的类
        /// </summary>
        /// <param name="notification"></param>
        public virtual void NotifyObserver(INotification notification)
        {
            object context;
            string method;

            lock (m_syncRoot)
            {
                context = NotifyContext;
                method = NotifyMethod;
            }

            Type t = context.GetType();
            BindingFlags f = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
            MethodInfo mi = t.GetMethod(method, f);
            mi.Invoke(context, new object[] { notification });
        }

Observer就相当于一个Command,其中NotifyObserver其实就是一个Command种的Execute,通过对context进行反射找到真正的类,然后根据method找到这类类中的具体方法,接下来传入参数执行即可。

还有一个就更明显了

        public virtual void ExecuteCommand(INotification note)
        {
            Type commandType = null;

            lock (m_syncRoot)
            {
                if (!m_commandMap.ContainsKey(note.Name)) return;
                commandType = m_commandMap[note.Name];
            }

            object commandInstance = Activator.CreateInstance(commandType);

            if (commandInstance is ICommand)
            {
                ((ICommand) commandInstance).Execute(note);
            }
        }

Controller中的ExecuteCommand方法,他直接根据类的名称反射一个全新的类,然后执行其中的Execute方法,简单粗暴。

所以说需要对行为进行"记录、撤销/重做、事务"等处理,使用命令模式是很不错的选择

相关文章

网友评论

    本文标题:Unity【话大】设计模式之命令模式

    本文链接:https://www.haomeiwen.com/subject/warnkqtx.html