在直播APP中虚拟道具系统的设计与实现

在公司直播产品的道具体系中,主要存在礼物、用户徽章、入场动画、弹幕卡等虚拟道具。现在的代码逻辑存在一个问题,每一种虚拟道具都是分开存储,逻辑方法也是分开实现,但是有很多需求往往都需要这几个虚拟物品结合使用(例如,登录送礼可以送上面的所有的道具)。

存在的问题

初始的时候,业务代码中要为用户增加上述的各种道具(只支持礼物、入场动画、弹幕卡),可以为用户添加一个虚拟物品,然后在虚拟物品使用的时候,再转化为对应的道具。

每一种道具,都有各自的使用效果,因此在业务上很难对这部分逻辑进行抽离。因此在实现虚拟物品模块的时候只单独把“用户获得道具”这个流程抽象出来,而用户使用虚拟物品的时候仍然是走各自的道具的具体实现逻辑。

在类结构上,主要分为UserVitemService这个上层类,主要负责对用户虚拟物品进行管理(新增和使用);以及各种道具相关的业务逻辑类。比如用户使用入场动画这个虚拟物品,将会获得一个入场动画,用户使用弹幕卡则将会获得弹幕的使用次数等,具体的类图如下:

虚拟物品关键类结构(第一版)

在流程上,主要分为用户获得虚拟物品及用户使用虚拟物品,具体的流程见下图:

用户获得虚拟物品流程(第一版)
用户使用虚拟物品流程(第一版)

之后,因为在某个业务需求需要让用户可以获得礼物、用户徽章、入场动画、弹幕卡、虚拟币等道具,但是原本的虚拟物品系统只支持礼物、入场动画、弹幕卡,而在直播项目中这样的业务需求还是很多的,之前也有同事使用做过这样的业务,他们的业务流程是这样的:

同事的虚拟道具获取拓展流程

但是上面的拓展流程存在一些问题:

  • 每一个要实现这样逻辑的人需要知道当前赠送给用户的物品属于什么类型,即每一个做相同事情的人都要维护相关的数据结构。
  • 代码的可复用性很差,上面的流程直接在具体的业务功能上进行实现,当其他业务需要实现相同的逻辑时,就需要复制相同的代码(当然,这个问题很容易解决,直接进行逻辑抽离即可)。
  • 无法复用虚拟物品的代码逻辑,虚拟物品有很多现成的可复用的逻辑,例如,物品的有效期设定与维护,关键日志的记录和用户获取记录的入库和恢复等等,而如果要为拓展的道具添加这些逻辑,就需要自己实现了。这个成本无疑是很大的,而且在之后对虚拟物品模块的完善也很难被更新应用到这些拓展的道具上来。

如何优化

那么要如何优化代码,才能让之变得更加的合理呢?我觉得首先要把握两个点:

  • 首先,每一个虚拟物品应该都可以分为两种属性,一种是其物品属性,一种是其效果属性。其中,物品属性表示其存在性,在具体功能上可以表现为每一个道具都对应着一个具体的数据实体,它可以出现在用户道具栏中,徽章库中,服务器的数据库中。而效果属性这表示道具的具体业务逻辑属性,比如用户使用徽章可以展示在个人卡片上,使用礼物可以给用户送礼,使用入场动画可以有入场特效等。
  • 其次,虚拟物品的物品属性由虚拟物品模块统一管理,而效果属性则交由具体的业务方实现。即,用户获得某个虚拟物品可以直接调用虚拟物品的接口,并最终将数据保存在虚拟物品模块中。然而在使用某个虚拟物品时,需要代由虚拟物品模块转交给具体的道具逻辑实现方处理。

根据以上两点,可以得出一个粗略的想法,首先,我们拓展虚拟物品的种类,即,让虚拟物品包含上面所说的所有的道具种类,这个需要做到数据实体上的兼容。其次,用户获取虚拟物品还是走之前的流程,即由虚拟物品模块统一管理,而在使用虚拟物品时,我们可以通过发送事件的方式,调用具体道具的业务逻辑方进行处理,大概的流程如下图所示:

用户使用虚拟物品流程(第二版)
为什么要通过发事件的方式来调用道具的使用逻辑,而不沿用之前的流程?

使用之前的流程的话,作为虚拟物品这个上层类如果需要调用具体的道具业务逻辑方法,我们大概可以通过两种方式实现,其一,使用模板方法模式,在子类中实现具体业务逻辑;其二,在上层类中引入具体的逻辑实现类,然后根据虚拟物品类型调用不同的类方法。第二种方案无疑是拓展性很差的,而第一种似乎没有什么问题,拓展性良好,代码看上去也会更有层次感,对比发送事件的方式也不差,或许更好,毕竟更符合线式的逻辑。

但是在这里还是选择了事件方案,主要是因为,事件处理机制很符合分布式系统的各种设计理念,事件或者说消息对队列是分布式系统中重要的解决方案,可以应用到多系统之间的解耦,分布式事务等场景上。而且因为直播项目还处于不断的开发阶段,我不知道之后直播产品的量会有多大,之后还会有什么样的道具产生,而使用事件,可以让我的系统可拓展性更强(可以很方便的接入到消息队列中)。

虚拟物品的物品属性

首先我们要解决一个问题,虚拟物品的物品属性有哪些?只有解决了这个问题,之后的一切才能进行。经过对各个虚拟道具需求的分析,我大概总结了以下属性:

  1. 道具标识属性,虚拟物品可以分为不同类型的虚拟道具,可以有礼物、用户徽章、入场动画、弹幕卡、虚拟币等,因此我们需要有一个唯一的道具标识属性来唯一定位到某一类型下的某个具体道具(例如礼物类型下的玫瑰花礼物)。
  2. 时间属性,虚拟物品可以设置物品有效期以及道具时效,有效期可以包括固定时间点的有效期,即虚拟物品会固定在某个时间点过期;以及相对有效期,即虚拟物品的有效期根据用户实际获取时间设定;而道具时效是指,虚拟物品可以设定只在指定的时间段内有效,过了时间段后,用户虚拟物品即刻过期。
  3. 展示属性,虚拟物品可以设定自己的展示样式,最终展示在客户端的可以与对应的道具不同,即,虚拟物品可以设定图片、角标和动画等属性。
  4. 使用属性,虚拟物品都是可以使用的,但是每种道具的使用效果由道具类型所决定,而每种道具是否可重复使用也由道具类型本身所决定,即,对于徽章类物品,其是可重复使用的,而对于礼物类道具,则使用后即失效。另外每种道具的使用条件都不同,他们可能都需要一些附加属性,例如,对于弹幕卡道具,我们使用这个道具时,会需要获得需要为用户增加的具体的弹幕次数。

虚拟道具系统设计

由于项目属于公司业务,这里去掉了具体的实现,下面是系统中的一些流程图。

虚拟物品实体类结构如下:

Vitem Classes

两个关键流程如下图:

虚拟物品缓存流程
用户虚拟物品更新流程

系统中主要组件之间的交互流程如下图:

Vitem-queryUserVitems(查询用户虚拟物品)
Vitem-userGainsVitem(用户获得虚拟物品)
Vitem-userUseVitem(用户使用虚拟物品)

你可能感兴趣的:(在直播APP中虚拟道具系统的设计与实现)