« DXT 图片压缩 | 返回首页 | 无欲则刚 »

模块的初始化

组件式的设计中,最难处理的就是模块的初始化次序和退出次序的问题。如果不考虑动态加载卸载问题,则可以简化一些设计。

退出问题解决起来最为容易,安全的退出唯一需要考虑的是对系统资源的释放。这是操作系统的工作,进程被杀掉时,所有占用的资源都会被安全回收,所以我选择的是不作为。

初始化部分要相对复杂一点,我把模块加载和初始化部分分开。加载的过程是静态的,无相互依赖关系的。实际上,做的只有代码和数据段载入内存的过程。(在实现上,要绝对避免隐式的代码运行,例如 C++ 中的全局对象的自动初始化)

初始化过程是惰性的,即:用到再调用初始化入口。每个模块都在自己初始化的时候去调用所依赖模块的初始化(实际上也必须如此,否则拿不到别的模块的句柄,无法使用其它模块内的方法),这样模块之间的初始化次序就自然规整了。只要不人为写出循环初始化的逻辑,是不会出错的。

实际操作中遇到一个问题,某些模块的初始化依赖一些参数。当需要参数传递的时候,初始化流程就变的复杂了。昨天同事提出一个需求:3d 渲染的基础模块需要一个窗口句柄来初始化自己,否则无法使用。那么依赖这个渲染模块的其它模块的初始化部分就必须也知道这个窗口句柄。而窗口句柄是由窗口管理模块初始化后,构造一个窗口才能得到的。其它模块均无法自行构造出窗口来。

我们上一个版本的设计中,模块管理器拥有一快公有数据区,专门用于模块初始过程的数据交换。这种类似 Windows 注册表的设计,隐隐的,一直让我觉得不妥。这次重构代码时,就把它从设计中拿掉了。

重构代码到今天,发现该碰到的问题依旧存在,需要想办法更好的解决这个问题。昨天晚上躺在床上把怪物猎人2中的轰龙一举干掉,一扫几天来的郁闷心情。突然来了灵感,找到一个很简洁的方案解决这个问题。

首先,任何模块的初始化入口依旧不需要传递参数。这如同单件的设计一样,单件永远是自行构造的。这样,每个第一次使用单件的人都有可能触发单件的惰性初始化。若单件的构造还需要参数的话,代码复杂度会上升许多,显然是不合理的。

让需要构造的单件自行读取外部配置来了解如何构造自己,这也是一种解决方案。数据驱动、符合模块设计的原则:能自己解决的问题自己解决,减少数据的传递。但这不是一个普适的方法。因为有些工作就是一步步进行的,我们需要上一步的结果来进行下一步工作。

其实,我们需要的只是一个独立模块单独负责模块初始化阶段的阶段性衔接。

还是以 3d 渲染模块和窗口创建过程的依赖关系为例子。事实上,上层的逻辑并不需要直接驱动这些底层模块的初始化流程,它们只需要在自己初始化时,这些底层模块都已整装待发。所以,我们写一个独立模块初始化掉该初始化的东西即可:在这里,我们随便创建一个窗口,得到窗口句柄,传递给 3d 渲染器初始化。这已经足够单元测试使用。当以后游戏的复杂逻辑需要自定义的窗口时,简单把它换掉就够了。我把这个衔接用的模块起名叫 launch3d 。

我们的单元测试程序,只需要简单依赖一下这个 launch3d 模块。它能保证相关的底层模块都初始化完毕。


这个故事给了我启发:面对二次开发者,引擎开放出来的不一定是上层建筑的接口。整个设计可以是平坦的,无论上层还是下层构件都可以是可定制和可替换的。这样才是良好的设计。

Comments

请问一下这篇文章让我困惑的地方,
您同时提到“任何模块的初始化入口依旧不需要传递参数”和“……随便创建一个窗口,得到窗口句柄,传递给 3d 渲染器初始化”。我不明白的是到底要不要在初始化的时候传递参数?如果不传递参数的话,那么是不是说要单独写一个函数来做初始化?如果这样的话,会不会写出一个使用了很多参数的初始化函数?何时调用这样的初始化函数?
如果您能提供一点简单的代码,我觉得大家会更容易理解(例如您的关于内存管理的文章)

不错 顶了

在设计时,对于全局的东西,我们总希望将其全局性的范围尽量的缩小,最理想的状态就是,这种全局性恰好只覆盖了哪些依赖于这个全局事物的模块。云风的做法,是否也是希望达到这个目的?

云风的做法,不过是将窗口句柄的全局性局限在了这个负责其他模块初始化的模块中。然后将这个窗口句柄传递给需要的模块,并在这些模块的内部做一份拷贝。使得窗口句柄的全局性,在这些模块的内部得以延伸。但是逻辑上全局的东西,还是回避不了的,只是如何的表达才能更加合理而以。

不知道我的理解是否正确。

说到模块的组织和架构设计,以及题目中的模块初始化,较之Spring,更有借鉴和学习意义的是HiveMind.

HiveMind中的Module,Service-Point,SymbolSource,Configuration ,Contribution 相信会对从事游戏开发,架构设计的朋友带来不少有益的启迪。

有心的朋友不妨了解下。

to 夕霞孤雁:

今天读了一下关于 spring 框架的一些文章。果然不错。

我们现在的模块组织方式和它非常类似 :D 只不过 C/C++ 语言都不提供元数据,需要多敲一些键了。IoC 的思想倒是共通的。

推荐Bob的书《敏捷软件开发》,书名是敏捷软件,其实内容则以模式和设计为主。

很想开发中国版的“模拟人生”,把美国的这个游戏形式放到中国这个环境,大家购买虚拟的土地、建房、交友、成家、立业。还可以设置虚拟的房产交易市场。最好是按照中国现实的城市小区来设置游戏模块,游戏玩到最后,可以将虚拟中人物让他们在现实的环境中开聚会,相互交流,把台下的世界搬到台上来,是很有卖点的。不过可能你不感兴趣,因为这个游戏中不打架的!

可以参考一下J2EE中的IoC思想,Spring框架。

要是能进网易就可以欣赏下高手的代码了:)

例子嘛 :D 只能看代码了。我的所有代码在公司内部都是公开的。

不放到公众网上是怕丢人。

blog 只为自己记录想法,没有教学的目的。

至于文字表达,实在比不上工作时的闲聊或是公司内的技术交流会。

我发现这个blog上的很多东西我都看不懂:(
可能是文字太难理解,而且缺乏例子吧。

万物都在变,唯模块化不变。

关于我对 COM 的看法可以看 blog 第一篇文章:

http://blog.codingnow.com/2005/09/about_com.html

模块管理很多东西可以借鉴下COM里的东西

云风,你的引擎的完成度到多少了啊?什么时候能玩到你做的游戏呢?

Post a comment

非这个主题相关的留言请到:留言本