业务开发中的小心得之一
首次接触移动端网络游戏的开发,自己做的小模块是家具一般的功能。
伴随游戏周期始终,不会有太大的变动,功能与其他系统关联不大,但是颇多来往,所以必须保证数据处理的逻辑正确。
小小的升级功能,沿用架构的处理方式,也要沿用自己业务处理方式。
分为以下四点:
1.代入场景思考
2.这一行代码做什么?实际上有没有做?
3.编写前,编写中,编写后分别要考虑什么?
4.简化代码
一:
想准确的处理好升1级/升10级,应该先分开实现,再整合为一个接口。
这是必要的且收益高的复杂化,也是为了最终实现简单化的复杂化。
升级,无非扣除银两,操作等级。
但是这两句话本身就不是明确的。
a.什么情况下要扣除银两=> 银两足够的情况下;
b.什么情况下要操作等级=> 升级成功的情况下。
再退一步,
c.你的操作数值是针对哪个大臣的=> 玩家是否存在这个大臣。
d.而发起请求的玩家=> 传入的数值是正确的吗?Session正确匹配吗?时效过期了吗?
发起的请求是正常游戏流程产生的吗?
e.有没有恶意发包的可能,那么参数有可能要屏蔽哪些情况?
一个升级功能,可以是流放的大臣恶意发包升级,也可以是玩家升了满级手快多误点了一下。
那么以a、b场景为例,银两不足的情况下,根据所在需求说明,假设大臣当前等级为99,99升100需要消耗银两100,000,玩家当前银两只有500的情况下,不予升级,但予扣款。
也就是玩家银两-500,并且保存升级银两进度,假设大臣等级为MinisterLevelConfig类型,其中有index表示等级,progress表示进度。则此时index值不变,progress=100,000-500=99,500
这个progress数值的意思是本级还需99,500才能升级。因此这种情况下不需要操作等级,升级过程不完整。
二:
当以上场景实际发生,那么再下一次升级这个大臣时,判断progress>0,因此正式扣款前,要先清空进度,本级升级金额应该为99,500,存在两种情况,一种是玩家银两足够,则进度清0,index++;
另一种玩家银两不足,则进度减去当前玩家银两,index还是不予操作。这两句话似乎没问题,但是脑袋瓜想当然的第二种情况,恰恰是我犯错的地方,当第二种情况,也就是当前大臣升级进度不为0,
那么此时玩家银两应该相对进度而言,还是相对本级升级银两而言,此时涉及到一个比较对象的变换。也就是每次玩家银两是否足够,取决于,相对于什么费用而言,然后才是数值上的比较。
因此,当我写this.m_UserMinister.OwnConfig.Upgrade<MinisterLevelConfig>(UnitOfWork uow(事务相关),int index,int progress)时,执行的效果并不一定是写出来的那样,还有细节上的变化。
三:
假设一、二都考虑到位的情况下。
编写代码前,要时刻检查命名是否正确区分了类的成员变量和方法的局部变量,命名看似无关紧要,但很有可能会造成难以排查的bug。
应对这一点的个人约束:当调用成员变量时,必须加上this。
编写代码时,可能为null的情况,和参数不满足操作的情况,发包的场景,需要用Throw new Exception的方式阻止代码继续进行。并且数据库的操作,都要在这些屏障之后,以免造成数据泄露。
编写代码后,复用的代码都整理为成员方法,不仅看起来优雅美观,排查问题时也能更有针对性,在进入和跳出某个成员方法时,测试用例报错,那么bug范围得到缩小,解决效率自然就提高了。
四:
简化代码,减少代码量,但不改变执行的效果。
通过大佬的分享,获得了几个简化代码的方法。
Ⅰ.
a.foreach
可以改用Enumerable.range(min,max).Each(t=>{
a[t]..
})
II.
if(a<100)
{
...A
}else if(a>=100&&a<200){
...B
}else if(a>=200){
...C
}
当if else 情况存在多种,代码看起来有点复杂,改用
IDictionary<int,Func<int>> aHandle=new Dictionary<int,Func<int>>{
{100,()=>A()},
{200,()=>B()},
{300,()=>c()}
};
Ⅲ.
延迟加载
上文有MinisterLevelConfig对象,当我需要取其值如果不用延迟加载,每次都需要查询数据库,但在数值变化之前,查询的结果都是一样的。
因此可以这样写
private MinisterLevelConfig m_MinisterLevelConfig;
protected MinisterLevelConfig MinisterLevelConfig {
get{
if(this.m_MinisterLevelConfig==null){
this.m_MinisterLevelConfig=DB操作
}
return this.m_MinisterLevelConfig;
}
}
这样可以只访问一次数据库。
但在数据变更后,缓存变量m_MinisterLevelConfig也要记得改变。

浙公网安备 33010602011771号