概述:
本文介绍一种“逻辑持久化技术”。目的是进一步提升代码复用程度。主要应用场景在游戏中,例如人物角色升级、事物队列冷却等。
前言:
开发游戏中,经常看到一些业务逻辑相似,但是又无法复用的代码。例如升级。
英雄:每100点经验升级1级。
骑宠:每100点经验升级1星,每12星升级一级。
如果用传统的设计思路,会得到以下代码片段:
USR_HERO { public int exp; public int level; } UsrHeroDao { public boolean upgrade( USR_HERO hero, int exp) { hero.exp += exp; if (hero.exp >= MAX_EXP) { hero.exp = MAX_EXP - hero.exp; hero.level += 1; } } }
如果是宠物,就写一套宠物的升级代码。这种代码开发多了,就开始觉得烦,但是不认真看又会出Bug。我们程序员尼玛怎么能每天都重复的干着这些无聊的事情??
于是我开始冥思苦想,如果这些能力是模块,一个对象安装了这个模块,就具备了升级的能力,那我就不用开发了啊。多爽??不断的冥思苦想,曾经还半夜在家里的大厅摸黑转来转去,大脑不断构造着各种架构,又不断的被推翻。
终于,有一天, 我走在回家的路上的时候,给我想到了!!!
(PS: 各位看解决方案的时候,也可以稍微1分钟思考下上面的问题)
核心思路:
首先要分析为什么代码不能复用。因为升级的经验值是值类型对象!这个就是一切的根源本质。可以想象下,如果把对象的经验、等级放入方法内运算,实际上对象的值是没有受到影响的,因为按值传递被拷贝了一份。
所以???把值类型转成对象类型,突然间一切都柳暗花明了。例如:
OrmInt { public int value; } USR_HERO { public OrmInt exp; public OrmInt level; }
看到这里,大家是否突然间明白了?突然间觉得高端大气上档次了?尼玛这可是我奋战几天的结果。我相信我不说,业界起码3年内不会有人往这个方向思考(臭美一下,各位大侠手下留情,千万别喷我。。。。。)
现在我把升级的方法修改一下:
UsrHeroDao { public boolean upgrade(OrmInt exp, OrmInt level, int exp) { exp.value += exp; If(exp.value >= MAX_EXP) { exp.value = MAX_EXP - exp; level.value += 1; } } }
怎样?是不是觉得爽了很多。
案例:
为了进一步说明这个“逻辑持久化”如何的高端,我举个我实际使用的例子, 使用了简化代码:
// 为OrmInt增加一个可升级的方法,返回升级对象。 OrmInt { public OrmUpgradable ugprade(OrmInt upgradeValue, OrmUpgradeLimit upgradeLimited) { OrmUpgradable value = new OrmUpgradable(this, value, ugpradeLimited); } } // 升级对象,支持链式编程,实现升级触发下一升级的效果 OrmUpgradable { private OrmInt value; // 被升级的对象 private OrmInt upgradeValue; // 当前升级的值 private OrmUpgradeLimit upgradeLImited; // 升级的上限对象 private OrmUpgradable head; // 链式升级的头 private OrmUpgrade child; // 链式升级的尾 // 触发下一个升级 public OrmUpgradable upgrade(OrmInt value, OrmInt upgradeValue, OrmUpgradeLimit upgradeLimited) { OrmUpgradable orm = new OrmUpgradable(value, upgradeValue, upgradeLimited); orm.head = this.head; this.child = orm; return orm; } // 开始升级 public boolean doWhile() { // 不断循环升级 if(this.value.greatThan(0)) { // 当前的升级上限 int upgradeLimited = this.upgradeLimited.getUpgradeLimit(); // 计算可升级的值的部分 并升级 int incValue = min(upgradeLimited.substract(this.value), upgradeValue); this.value.increase(incValue); //判断是否升级 if(this.value.greatEqualThan(upgradeLimit)) { // 链式触发后续的升级 if(!this.child.doWhile()) return true; } // 更新剩余可升级部分 upgradeValue.update(upgradeValue.substract(incValue)); this.value.update(0); } return true; } }
使用方法:
p.value.upgrade(11, 10)
.upgrade(p.value2, 1, 10)
.upgrade(p.value3, 1, 10)
.doWhile()
这段代码用起来简单,但是原理有点复杂。
- 首先这是个链式升级。当exp值增加到达了最大值,则触发下个对象level进行增加,一直触发到最后。然后一个循环。
- 其次,exp不断升级,直到可升级的值用完了。感觉就像一个储水池。
- 最后,升级上限我用了一个对象OrmUpgradeLimit,原因是实际项目中,当用户的等级不同的时候,当前等级经验值上限是不一样的。所以OrmUpgradeLimit实际上内部包含了level这个对象。而由于level是类型对象,因此在升级过程中,升级上限是动态变化的。
小结:
本文抛砖引玉,介绍了一种非常强大的“业务逻辑持久化”技术。本质就是值类型转对象类型;对象类型除了包含数据外,并带上处理方法。
这样,这个对象复制给了Orm,Orm就具备了对应的能力。所以我命名为“业务逻辑持久化”,因为我把逻辑放在了持久层。
扩展阅读:
实际上现在的业务逻辑操作,都是围绕着数据。
逻辑更确切的说,就是围绕相互有关联的数据字段进行逻辑操作。 思维发散下,就明白。这个已经不是对某个对象进行操作了。
英雄有经验等级、坐骑也有经验等级,但是升级这个操作实际上是针对经验和等级这2个数据建立关系,而不是英雄和坐骑。
这个技术国外叫做:functional reactive programming
Hudak, Paul (September 1989). "Conception, evolution, and application of functional programming languages" (PDF). ACM Computing Surveys 21 (3): 359–411. doi:10.1145/72551.72554.
下期预告:
领先业界3年的游戏开发技术——顶级数据库持久层的设计。
目前最流行的数据库持久层是什么?Hibernate?ADO.NET?不,Hibernate从出生开始,我就觉得他实在太落后了。欢迎关注6月份的主题——顶级数据库持久层设计。
关于我们:
我们来自Pixysoft独立游戏制作人。我们的目标是培养早就游戏行业的独立制作人,提供一切相关的技术文档资料,从前端到后端、策划、数值、美术全方位进行培养。
欢迎加入我们的群:95755843
本群每月1日~10日为开放日,不限条件加入。11~30日为闭关日,除了成员邀请外,不对外开放,进行封闭培训。
本群关注的是思想的交流,其次借助开源平台共享资源。
欢迎游戏爱好者加入。