编码规范中的奇淫邪技(个人向
前言
上一篇讲了我在工作中遇到的”问题”,不应该触碰的禁忌.所以这篇文章准备记录一下我在工作中..算是得出的结论吧,总之就是在工作中我认为这些做法会有各种”好处”,比如代码量少,易阅读,易添加(功能)等.
如果有不同意见或发现我的错误想法,欢迎下面评论指正.
目录
先乘后除
正如上一篇中提到的”英雄事件”,修改了几次,浪费了不必要的时间,所以在那时候我们也规定了,如果在乘法不爆long long
的情况下一律先乘后除,不要使用浮点数,这样不仅在效率上能够得到好的效率,也避免了浮点数带来的各种意外.这是为什么呢?因为,假设有一公式D=A/B*C,结果向下取整,再假设A=20,B=30,C=10,D=A/B*C=20.0/30*10=6.666667向下取整为6..我们令E=A*C=200那么利用先乘后除就是D=A*C/B=E/B=200/30=6(计算机中整除无小数),结果是一样的,但在此没有用浮点数,效率得到了微妙的提升.假设是向上取整,原式D=20.0/30*10=6.66667=7..换成先乘后除就需要改一下公式成为:D=E/B+(E%B!=0)=200/30+(200%30!=0)=6+true=7,加后面那个尾巴是为了在不整除的情况下结果加1,保证是向上取整这里也避免了浮点数的使用,结果并没有误差.所以在工作中我一般是不会会浮点数的除非非用不可.
函数指针
这虽然是在工程特别特别常用的东西.但对于在学校的时候没这样写过的我来说,在写完一个又一个的时候,是无比的兴奋的,我觉得我用得越来越妙.C++
中有一个名叫std::function<t>
的东西.就是函数指针,函数指针的妙用,除了回调什么的,我最常用的大概就是用来省代码省事吧.举个最近的例子.
上周花了一周做了市场模块.市场物品各类目前只有两种,但以后会变多,比如做活动会增加商品等.在商品界面,有八个格子,每个格子一种商品,我在多个地方需要判断是哪种物品:
1, 初始时显示物品图片以及数量等简单信息
2, 点击图片时显示详细信息,是在弹出一个新界面弹出显示.
在我现在头脑还比较清晰,对代码还有印象的时候,你每添加一种商品的时候,我会记得我需要写一个新商品的详细信息界面,写一个读取简单数据的函数并在点1所在的地方去加一个case
,在点击的地方加一个case
,如果在游戏上线后,说要做活动,加几个新商品卖,我依然记得另个新商品的详细信息界面,写个简单数据读取函数。但我可能只记得要开始显示的时候要加个case
,就不一定记得点击的地方要加个case
了.所以在运行测试之后我才会发现还要在点击的时候加个case
才能保证弹出来详细界面,太麻烦,而且这里只有2个地方要加,要是以后多个地方要加,那岂不是得好多次而且能测试完全才能补齐.为了避免这种不必要的浪费时间,和无限加长的冗余代码(无止尽的case
),函数指针就锋芒显露了,我把读取简单信息的函数,存在一个数组里,详细信息界面的创建函数存在一个数组里,然后在一个统一的函数中维护他们,在使用的时候直接就是if(apkFunc[TypeOfProduct]!=nullptr) apkFunc[TypeOfProduct(parameters)
就可以了,只需要一两行代码,代码量减少了,而且在加新商品进来的时候只需要在那个统一的函数中去维护这些函数指针即可,这样也不会忘记某个地方没更新.
这在只有两个地方的时候体现可能不太明显,但想象一下如果有十个八个地方需要case
,是不是就可以省去一大堆麻烦了.
不过这也并不是绝对优美的,因为这样导致了可读性变得差了一些,想象一下别人看你代码的时候,可能知道你在某个地方的意图是读取简单信息,但想要跟下去看读取信息函数的内部实现,根本没法跟啊,得去那个统一的函数里找到他想要看的那个函数的函数名.然后才能跟.
无限new制
这个技巧没啥技术含量,或者说根本算不上是技巧.
- 一个游戏必然是伴随着动画的,每个动画都需要去创建,每执行一次都要去
new
一次。这样显然是不太能接受的,我们应该把重复执行的动画,只new
一次,存起来,一直用,无限new
的代码是非常可怕的,特别是小内存. - 在有的界面,需要一直刷新,比如说我项目中的造兵界面,为了使进度条显得是慢慢移动的,所以用了每一帧都去刷新一下界面,这里就出现了比如对
Text
的setString
,每一帧去set
一次,而在每次set
的时候为了方便都是StringUtils::format("%d",iNumber)
这个函数的实现是先malloc
了100k内存,然后sprintf
进去,这样看起来比较方便也好理解,但实际上非常可怕的,无限的new
100k内存,虽然都会释放掉,这里有个可选方案是,不要在堆上申请,改成在栈上申请内存,定义临时局部char
数组,避免了这样的担心.
所以避免无限new
的方案,一是申请一次存起来复用,二是改成栈上申请,效率又高又可靠.
懒得写枚举
写装备系统的时候有个操作是脱装备,穿装备.两种状态,我当时想着就用个bool
值0和1表示穿和脱好了.后来再去看的时候发现,并不能立刻反应过来0和1分别代表啥.准备写个注释在旁边,突然回忆起什么来,然后改成了用int
来表示脱和穿,但不是只有0和1两个状态,而是变成了+
和-
两个状态.我用int
接收参数,传入'+'
或者'-'
这样一来,又省略了枚举,又能清楚的表达脱和穿两种状态.当时觉得我太机智了以前都没这样用过.其实是因为我回忆起,我以前看磊哥(一同事)的代码发现他有类似的用法,在战斗的时候要传入一个参数表示攻打方和被打方看见他传入参数是'A'
和'B'
,觉得这样太机智,一眼就能看出结果又不用写个枚举.
为什么不用char
呢,一是因为int
的范围要广些,可以容纳三四个字母,假设要表示你和我,我可以传入'YOU'
和'ME'
. 二是因为,在我的认知中,一直是少量,处理int
比处理char
要高效些.