前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >游戏服务端开发的逻辑解耦思路

游戏服务端开发的逻辑解耦思路

原创
作者头像
春帆
发布2018-08-18 11:54:09
1.2K1
发布2018-08-18 11:54:09
举报
文章被收录于专栏:nothingnothing

基本 CS 框架时期

最开始的代码库中,主循环收到协议后,通过手写的路由关系转交给对应的业务逻辑类实现。

通过依赖倒置解耦注册单点

更进一步的模式是将业务逻辑明确地拆分为 n 个 logic 类,路由关系通过依赖倒置转交给 logic 类自己注册,把部分协议注册到自己名下。主循环通过注册表查找 logic 进行分发。这样可以更方便地从切入层做一些校验和统计的工作,整体给框架的信息更多,更可控。

这种模式减少了大量重复代码,可以倒置的不仅是协议依赖,还有其他内部协议,db 请求等。最终将一组玩法归类到一个 logic 中实现。

常见的问题

再往前进一步,logic 也会变得越来越臃肿,例如经典的道具,任务等。这类语义在经过拓展,变体之后,实际已经是多个不同的实现逻辑,放到单个 logic 承载导致非常臃肿。

另外,部分逻辑需要多个不同的进程配合。如果一个 logic 承载了 A 进程的数据 a,在 B 进程中就无法直接用,这里很多开发者很容易开始复制代码到 B 中。例如校验是否过期的逻辑,很多同事直接在业务中写运算,后来过期逻辑调整了,如果没有封装,这里就需要人工 review 代码去改逻辑,而且非常容易遗漏。道具有道具的过期逻辑,任务有任务的过期逻辑,支付有支付的过期逻辑。如果不通过封装分清楚,代码的可读性将非常差。

这种 logic 的模式代码膨胀之后还存在依赖混乱的问题,例如 logicA 中有简单逻辑 a1,复杂逻辑 aaa1,aaa1 依赖 logicB 中的数据,logicB 中的接口又依赖 a1 提取 A 中的数据,就出现了依赖圈。很多情况下,是由于 a1 根本和 logicA 没关系,可以拆分出来而没有拆分导致的。这里很多人都会开始复制代码快速跑通,然后就不管了,因为这种情况出现的大量复制简直是万恶之源。

如果要解决这些问题需要重构代码,我坚持小步重构的思想,随着需求迭代,触及到改动的地方,准备好测试之后,一定要把能优化的都尽量优化干净。如果因为能 work 而应该调整的不改,后面一定一定会有坑的。

通过 System 拆分逻辑

后来我们拆分出了更细的逻辑系统,这里借鉴了 ECS 中 System 的设计,传统的 logic 由于需要维护一些内存的东西,都是一个单例对象。但是新的 System 由于没有 logic “承载一个玩法” 这样的包袱,足够简单到可以严格只用静态函数描述逻辑。

在有了 System 拆分逻辑之后,logic 就只作为接入层。我们还做了一件事简化这个接入层,通过使用函数对象,把 logic 的注册直接调整为消息到函数的注册,在 logic 和 base 之间加入了一个 svrbase,用来做进一步的校验协议,校验 svr 的数据如 Player 对象等,这样在最终的 logic 中完全省略了逻辑之外的代码,可读性极大地提升了。同时从这个 svrbase 层起,所有接口只接收引用,指针参数容易造成很多指针参数归属权不明确,代码中出现大量浪费的指针判空逻辑等。使用引用意味着直接操作数据,在哪里校验,在哪里加工,每一层的语义更加清晰。

System 的主要设计思想是精确。例如任务的 System 叫做 BaseTaskSystem,这里是最简化的任务,只有任务配置,任务进度这两个属性。再上一层根据不同的任务类型,任务玩法分为 ATaskSystem,BTaskSystem,分别处理不同 Task 的逻辑。对于任务配置的获取,任务数据的校验,进度迭代,统一调用 BaseTaskSystem。这样 A B 中只需要处理 Base 不知道的信息。精确的好处就是下层可靠了,上层效率就高了。最后到 logic 层基本就是纯语义的转述,没有代码复制,开发效率变高了。这里对于没有特殊逻辑的任务,我们没有创建代理而是直接默认用 BaseTaskSystem,可以减少工作量。

这里只使用 ECS 中 S 的部分,其实在数据层面由于我们大部分数据是协议数据转译,都是 POD Type,在 S 中只操作数据和引用的话,C 的部分是天然实现的。E 的部分由于我们是 CS 模式,还没有很强的循环更新需求,因此暂时没有用上。

总结

整理一下,System 的特点是:

  • 全静态函数,只有逻辑。
  • 只接收引用或传值,只操作直接安全的数据。每个 System 只操作自己的数据
  • (由于 optional 还没有实装,可以返回指针用于部分场景)
  • 没有继承,没有多态。对其他 System 有合理依赖直接调用,必要时通过重构来优化依赖关系。

这样抽象下来,很多 System 由于自身的简洁性,可以移动到无业务相关的公共库中。而有业务依赖的 System 则保留在对应的 svr 中。logic 之间和不同进程的逻辑之间可以复用公共库的逻辑,跨进程的依赖关系也变得清晰。整体代码质量可以得到提升。在铺功能的过程中可以享受业务拆分复用的红利,开发效率可以大幅提升。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本 CS 框架时期
  • 通过依赖倒置解耦注册单点
  • 常见的问题
  • 通过 System 拆分逻辑
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档