• 游戏编程模式之命令模式


    • 将一个请求(request)封装成一个对象,从而允许你使用不同的请求、队列或日志将客户端参数化,同时支持请求操作的撤销与恢复。

    • 命令就是一个对象化(实例化)的方法调用(A command is a reified method call)。

    • 命令就是面向对象化的回调(Commands are an object-oriented replacement for callbacks)。

      (摘自《游戏编程模式》)


    简单的例子

      上面对于命令模式的定义该怎么理解呢?我们用一个很简单的例子进行介绍。一个简单的if-else实现的“满足条件->执行事件”功能,我们可以这么写:

    if(A is True)
        DueA()
    else if(B is True)
        DueB()
    

      上面的代码是一种硬编码的方式。其问题在于,当我们想要改变某个条件下执行的事件内容,需要重新修改代码并编译出可执行文件。若是以这种方式编写游戏的按键输入事件,用户就不可以自定义按键映射,然而现实是,许多游戏允许用户配置他们的按键与游戏行为之间的映射关系。因此,将DueA和DueB这类方法事件包装成一个统一父类的命令,便可以实现自定义配置的功能。修改后的代码如下:

    
    class Command
    {
        public:
            Excute();
    }
    
    class Command1 : Command
    {
        public:
            Excute();
    }
    
    class Command2 : Command
    {
        public:
            Excute();
    }
    
    Command* commondA;
    Command* commondB;
    
    //if...else可写为
    if(A is True)
        commondA->Excute();
    else if(B is True)
        commondB->Excute();
    

      当我们需要改变满足A True条件的事件内容时,仅需要改变变量commandA指向的命令对象即可。将事件函数、命令封装成对象以实现不同条件执行映射,即为命令模式


    再一次解耦

      如何将硬编码逐渐编程复用性高、耦合性低的代码,这就是编程模式的工作。那么上面的例子还改进吗?我们可以看发现commondA->Excute() 这一个执行过程仍旧是一个方法,也就是说,即使我们实现了配置事件条件映射关系,但我们仍然无法配置事件的内容,特别是针对某一个执行命令的对象。

    • 我们想想语文中对“命令”这一词的定义:

    命令释义:上级对下级有所指示 (摘自百度百科)

      命令就表示了一类相同的操作,我们作为上级在某种条件下对“某个下级”提出需要执行的内容。结果就很明显了,我们还可以把执行命令的对象从Excute()方法中解耦出来。

    class Command
    {
        public:
            Excute(Object executor);
    }
    
    class Command1 : Command
    {
        public:
            Excute(Object executor);
    }
       
    class Command2 : Command
    {
        public:
            Excute(Object executor);
    }
    
    Command* commondA;
    Command* commondB;
    
    //if...else可写为
    if(A is True)
        commondA->Excute(<命令执行对象>);
    else if(B is True)
        commondB->Excute(<命令执行对象>);
    

      注意:此解耦是根据需求而定的。部分代码不需要多个命令对象,则可以将代码简化而不需要这一层解耦操作。


    撤销与重做

      在《游戏编程模式》此书针对命令模式的介绍的最后,提出了“撤销与重做”的功能。这就是命令模式针对功能拓展的最好例子。
      相关代码不再进行详细说明,我们谈谈具体的思路。在命令模式中,我们将命令封装成一个类实例,其Execute()方法设定了玩家的操作方式,那么在类中,我们也可以编写一个Undo()方法用于还原Execute()方法执行的操作。这仅仅要求在Command类中要记录一些Execute()方法中改变的必要数据即可。
      如何进行逐步的撤销呢?这时候,我们需要编写一个Command队列存储和管理Command实例。当玩家需要撤销时,Command队列进行出栈,并调用出栈实例的Undo()方法。当队列为空时,证明我们之前修改的内容已经全部撤销完毕。

    总结

    • 命令模式极大程度上的避免了对代码灵活部分进行硬编码。
    • 命令模式本质就是将函数式事件封装成一个Command类实例,实例中实现了我们对命令的需求功能(例如对命令对象的执行、撤销命令功能等)
    • 可以把命令模式看作是类形式的回调函数,将事件作为参数化并自定义条件-事件映射、执行内容。
  • 相关阅读:
    app store connect待提交修改版本号
    tableview无法调用touchesBegan
    UISearchController遇坑总结
    中文空格 占位符(OC)
    OC校验字符串是否每个字符都相同
    IPA processing failed
    关于静态代码块和非静态代码块执行顺序(了解这些你就了解所有)
    MapReduce
    大数据---HDFS写入数据的过程
    大数据之--------hadoop存储(HDFS)
  • 原文地址:https://www.cnblogs.com/ZhuSenlin/p/15423543.html
Copyright © 2020-2023  润新知