美文网首页
2020-11-18【设计模式】行为型模式&解耦型模式

2020-11-18【设计模式】行为型模式&解耦型模式

作者: 持刀的要迟到了 | 来源:发表于2020-11-18 20:22 被阅读0次

    行为型模式 (游戏编程模式p139)

    本篇的模式,可帮助快速定义并提炼大量高质量且可维护的行为。
    类型对象让我无需定义实际的类,就可以创建各种类型的行为。
    子类沙盒提供了一系列安全的基础功能函数,可以通过组合这些函数定义各种行为。
    最高级的选择是字节码,可以将行为从代码,完全转移到数据中去。

    总结:
    类型对象,就是很简单的给对象一个枚举值的type。(或者是一个唯一的序列化文件,如ScriptableObject,或者一行数据表的ID,里面除了type,还有其他类型相关信息,如描述,所属父类型,等...)
    子类沙盒,就是很简单的接口继承。接口本身并无功能实现。
    字节码:啊,是Lua,虚拟机。那没事了。

    字节码

    • 先数据后编码

    我们要让它易于修改,易于重新加载,并且在物理上与游戏的可执行文件相分离。
    这种形式更像是一种“数据”。我们可以在单独的数据文件中定义行为,游戏引擎以某种方式加载并“执行”它,那么上述问题就得到解决。

    • 解释器模式

    大概就是自己做了一下动态运算符,“解释”静态的数据含义 。比如,写一个加法类,来解释“+”字符串。
    问题:太慢了,而且占用大量内存。

    • 虚拟机器码

    当我们的游戏运行时,计算机并不会去遍历c++语法结构树,而是执行我们在编译期编译成的“机器码”。为什么需要机器码呢?

    • 高密度。它是坚实连续的二进制数据块,绝不浪费一个子节。
    • 线性。指令被打包一起顺序执行,不会再内存中跳跃访问。(除非你编写了控制流)
    • 底层。每个单独的指令仅仅完成一个小动作,各种有趣行为都是这些小动作的组合。
    • 迅速。以上几点让机器码急行如风。当然包括,机器码由硬件实现,更快。(NB!)
      听上去激动人心,但我们不想直接用机器码编写法术。为用户提供这些玩意儿就是自找麻烦,而且不安全。因此只能在机器码的效率和解释器模式的安全性之间折中考虑。

    我们不去加载执行真正的“机器码”,而去定义自己的虚拟机器码。我们再游戏中实现一个执行它们的模拟器。这些虚拟机器码和机器码相似(高密度、线性、相对底层),同时它完全受到游戏本身的安全管理。
    我们称这个小型模拟器为虚拟机(VM_VirtualMachine)。这个虚拟机所执行的语义上的“二进制机器码”称为字节码。它具备在数据内定义对象的灵活性和易用性,同时也比解释器模式这种高级呈现方式更高效。

    如果功能清单不是太复杂的话,这个方案将非常可行。即使最终没用上,至少也能对Lua及其他基于该原理的语言有更好的理解。

    PS:JIT_Just In Time编译器,可以很快的把语言翻译成机器码。而机器码就是上面说的那个牛逼玩意儿。

    • 字节码模式

    指令集定义了一套可以执行的底层操作。一系列指令被 编码为字节序列。虚拟机逐条执行指令栈上的这些指令。通过指令组合,即可完成很多高级行为。

    • 使用情境

    想一下Lua。再见。bye~ bye~
    就是语法解释器。对于一个程序员来说,绕了一圈又一圈。这玩意儿写出来给别人用的。

    子类沙盒

    "使用基类提供的操作集合来定义子类中的行为"

    • 动机

    class SuperActorBase
    class Hero1 : SuperActorBase

    如果此时我们编写这个基类,会发生什么?

    • 这将产生大量冗余代码。当我们完成冰冻射线、火焰射线、芥末射线时,会发现它们在实现上都极为相似。如果在实现时没有整合起来,那么将会产生大量重复的代码和重复的劳动。

    • 游戏引擎的每个部分都将与这些类产生耦合。在未深入了解所有细节之前,人们会编写一些代码去调用原本不应该与SuperActorBase产生关系的子系统。就算我们将渲染器漂亮地划分成一些结构清晰的层,并只允许其中一层被图形引擎之外的代码所使用,我们也仍坚信,最后SuperActorBase代码会入侵到渲染器的每一个分层。

    • 当这些外部系统需要改变的时候,SuperActorBase的代码很可能遭到随机性的破坏。一旦我们各种SuperActorBase与游戏引擎的零散部分产生耦合,改变那些部分,无疑会影响到此Super类。这就十分蓝受了。

    • 定义所有Super类中的不变量时很困难的。

    • 总结:基类类似一个接口。接口里没有具体实现,别人和它的耦合也都是通过接口。这个设计模式就叫子类沙盒,它会催生一种扁平的类层次架构,我们的继承链不会太深,但是会有大量的类和Super类挂钩。 继承自基类很容易造成耦合,但是扁平的继承树会比长纵深的继承树更易用。

    • PS:从另一个角度说,所有的耦合都被聚集到基类,子类现在便与其他部分的代码划清界限。理想状态下,你的绝大部分操作都在子类中。这意味着我们的大量代码库是独立的,并更容易维护。
      但是如果发现,本模式正把基类变得庞大不堪,那么就要考虑,把一些提供的操作,提取到一个基类能够管理的独立的类中。(组件模式可以提供帮助)。

    解耦型模式 (游戏编程模式p194)

    组件模式

    unity的gameobject就是遵循组件模式。
    gameobject是一个空的对象,但是你可以往上面 AddComponent。
    各个组件之间没有直接的联系,又各有各自的功能。
    自定义组件:继承自MonoBehaviour

    组件之间的消息传递:

    • 公有信息放在gameobject上(共享数据)
    • 直接引用(如自定义的mono上,引用其他组件)
    • 通过传递信息的方式(sendEvents to gameObject, gameObject resend to other components)

    相关文章

      网友评论

          本文标题:2020-11-18【设计模式】行为型模式&解耦型模式

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