浅谈游戏开发中常见的设计模式

前言  

由于游戏开发在架构上要考虑性能和实际需求,在尽可能不引入第三方库、框架的前提下进行开发,因此在编码时候会常常用到设计模式对代码进行复用,对业务逻辑架构解耦,尽可能减小hard code。编程

单例模式(Singleton Pattern)

单例模式常常会用在逻辑上惟一的对象(一般用于重量级资源)上,如Factory、Context、Resource、Pool和Service等,但在代码细节上须要注意开放出去的接口以及该接口的严格语义。单例模式一般带有生命周期函数,有利于结合框架本身的生命周期管理进行初始化或销毁操做。在开发过程当中会遇到一些很差的例子,如变量都是类静态成员变量、方法都是静态方法,这样写的代码可能在调用上的结果符合“单例”这个语义,可是会让其余人感到困惑。设计模式

工厂模式(Factory Pattern)

使用工厂模式来统一建立对象有利于管理对象的生命周期,一般会组合单例模式、代理模式、策略模式,对复杂的对象进行组装,对建立的对象进行统一管理。统一对象入口的好处在开发初期可能不明显,但随着开发进度的推进,业务的愈来愈复杂,统一入口容易更好地跟踪对象的生命周期,也容易的对某类对象初始化时进行统一的操做。网络

策略模式(Strategy Pattern)

对于一些逻辑类似但实现的细节不一样粒度又比较细的业务,能够将保证语义粒度适中的接口提取出来,按不一样的实现逻辑来封装成不一样的策略,在经过策略容器(一般是工厂容器)在上层业务中进行组合调用。这样既能够保证逻辑结构的清晰又便于扩展。在游戏开发中,状态机就是一个使用策略模式的例子,状态机自己就是一个策略容器,它将与状态相关的行为从大量的跳转中抽离处理,让代码结构更清晰明了。代码结构越清晰,跳转越少意味着出现BUG机率越低,调试起来更容易。我的以为策略模式的关注点应该在接口的粒度上,它跟代理模式不一样,要求粒度适中,根据具体的业务去动态选择策略使得封装的代码脱离于客户代码。使用策略模式来解耦代码是一个很好的选择。架构

代理模式(Proxy Pattern)

代理模式跟策略模式其实很类似,粒度比策略模式粗,用于控制访问对象。举个例子,有一个复杂的数据对象有一个通用的二进制序列化接口,由于业务扩大,序列化数据愈来愈大,而网络层限制了协议的最大长度。这时是须要改网络底层?把公共的序列化接口改掉?仍是在调用的代码上hard code一次裁剪后的序列化代码?答案是显而易见的:只须要一个面对这个协议的对象访问器,而这个访问器只须要根据业务实现裁剪后的序列化接口。使用代理模式,更好的保护对象的封装,让频繁改变的业务跟稳定的对象隔离开来。框架

观察者模式(Observer Pattern)/订阅发布模式(Subscribe/Publish)

这两个模式主要为了解耦独立对象间的耦合,在这里放在一块儿来说,由于这两个模式主要区别在结构上,观察者模式是直接耦合的,发布订阅模式是松散耦合的。在游戏开发上中常常看到XXXListener,这就是用了这两个模式(大多数用订阅发布模式)。在游戏开发中,除了框架提供的事件生命周期外,其实能够用这些模式去松散具体业务的耦合。举个例子,在一个复杂的养成系统上有不少条养成线,养成线互相有勾连,养成线的变更除了系统与角色的交互操做外,其余的养成线的交互操做应该只停留在这个养成系统自己,这时候就须要观察者模式/发布订阅模式将这些养成线的交互隔离开来。dom

模板模式(Template Pattern)

这个模式偏向于框架编程,在实际开发中须要考虑到common——domain的比重,在考虑实际须要的抽象程度和业务的粒度。抽象程度过高会致使开发效率下降和实现难度增大,抽象程度过低又会致使业务性太强以至很差扩展和维护,这是一个值得深思的问题。函数

组合模式(Composite Pattern)

面向对象最重要的复用方式多态和组合,组合模式将不稳定的对象隔离,以树状结构链接起来。使用组合模式的好处是频繁改动的部分不会影响到稳定的总体,但缺点是不能使用多态这个语法糖来进行直接复用。在开发中严谨地使用组合模式和继承会让代码结构清晰和更从容面对业务地变动。关注点在于变的部分,就像阴阳两极同样,在实际开发中怎么用组合/继承也是一个值得深思的问题。性能

后话

其实还有不少设计模式我没有提到,由于个人实际开发场景不多遇到。我认为,设计模式是死的,而业务是活的。按照《Clean Architecture》中Bob大叔介绍的软件设计原则,再结合实际加以运用,不断地提炼代码,相信你也会发现编码的乐趣。本人拙见,谨在此抛砖引玉。编码

相关文章
相关标签/搜索