游戏主程序和外观模式

1 子系统整合

游戏一般都会分成多个子系统,如关卡、事件、成就等等,这些系统会互相调用彼此的功能,传递信息。有些子系统还需要初始化和释放资源。初始化放在哪里合适呢?一个朴素的思想是某个状态类涉及了哪些子系统,就在这个状态类中初始化。

我的世界场景类: 场景状态类
{
    游戏事件系统
    时间系统
    聊天系统
    物品系统
    ...

    构造函数(拥有者): base(拥有者){
        赋状态名
        初始化子系统
    }
    初始化子系统(){
        游戏事件系统实例化
        时间系统实例化
        ...
        游戏事件系统初始化
        时间系统初始化
        ...
    }
    更新子系统(){
        游戏事件系统更新
        时间系统更新
        ...
    }

}

上述方式虽然简单,但有一些缺点:

  • 该状态负责了太多功能,本来应该是管理该状态的,不应该负责初始化子系统,违反了单一职责原则
  • 难以重用。因为包含了太多的子系统初始化,关联了太多子系统,必须删掉才能重用

2 外观模式Facade

GoF对外观模式的定义是

为子系统定义一组统一的接口,这个高级的接口会让子系统更容易被使用

以车为例类比外观模式,方向盘、踏板、仪表盘等就是汽车引擎系统、悬挂系统、传动系统等的“高级接口”。司机只需要通过这些高级接口就可以开车。外观模式的重点就是隐藏系统内部互动细节,并提供简单方便的接口。

对应到程序中,就是一个整合所有子系统,负责子系统初始化、更新、释放的接口类。这个类是游戏主程序,提供了界面让客户端使用。因为对于其他子系统的开发人员来说,只需要了解主程序即可,其他子系统的具体流程不用深入了解,因此外观模式有助于协作开发。

这个接口类在状态模式的文章中已经出现过,在那篇文章里用“游戏逻辑“代替了。当时在“我的世界场景”中通过调用游戏逻辑的初始化、更新方法来操作系统运行,实现解耦。这里详细说明

我的世界游戏逻辑
{
    //子系统声明
    时间系统
    事件系统
    物品系统
    怪物系统

    //我的世界场景调用下述方法实现场景初始化和更新,实现解耦
    初始化(){
        事件系统实例化
        时间系统实例化
        ...
    }
    更新(){
        事件系统更新
        时间系统更新
        ...
    }
}

3 补充

解耦是外观模式最大的优点。缺点就是子系统太多会导致外观模式的接口类庞大难以维护。这时候需要整合子系统,或者结合其他设计模式。

其他应用场景:

  • 网络引擎将各种连线、事件等子系统通过外观模式整合管理
  • 数据库引擎也通过外观模式封装数据表的操作供其他没有数据库背景的开发人员使用