使用闭包和lambda解决问题与常规方式解决问题的对比。
2013-10-23 10:33
441 查看
先来描述一下问题吧,游戏中的物品原来只有一个属性加成:攻击,防御,获得经验加成,金币加成,等等。现在要增加一个属性,这个属性可以为之前的属性之一。
这个属性加成涉及到类里的三个属性,value,type,grow_value,在战斗,角色属性预览,还有物品的详细信息里面都有使用到,type表示的是这个加成的类型,value表示这个加成的值,grow_value表示这个加成的成长值。现在加了一个属性,之前的计算方法就都不能用了,而且变量名字也得改,在添加后应该变成,value1,type1,grow_value1,value2,type2,grow_value2,之前所有计算的地方都需要修改,UI显示部分也需要修改。而且这些改动很多,很无脑,很繁杂。(也许有好的修改方法,知道的请在评论里面提示一下。)
上头就把这个任务给了我,然后告诉我应该这么改,就没了。我改了几个地方发现异常蛋疼,于是就想着有什么好的解决办法。学了1年多的函数式编程,现在终于被我用上了。
可以把新的属性加成看成是一个新的物品,这个物品只有3个属性value,type,grow_value,我们现在需要的是一个原来的物品附加一个新的物品,这样原来计算的方法都可以使用了,我们要做的只是再计算一次。并不是所有的物品都有两个属性,只是新加的一些物品才会有两种属性,所以再计算的时候判断一下这个物品是否有附加的物品就好了。下面用代码简单地描述一下各个类的修改,我使用的是AS3,类似JS,可以把函数作为一个对象来使用,支持闭包和匿名函数(lambda)。
第一步在原来的类里面添加三个附加的属性,以及一个attachItem
新加的三个属性只在读表的时候用到。另外在使用这个类作为数据,并将这个类的数据进行加工后提供给外部的类中添加两个方法和一个属性。
说明一下第一个函数handleProp按照注释说的,可以这样修改原来调用那3个属性计算的方法。比如原来是:
只要这样处理就好:
下面说明一下原理,将原来的计算过程作为一个函数传入CEquipment类中,在handleProp中立刻进行调用,这样就计算完成了第一个属性。然后handleProp将函数传给了handlerAttachEquip函数,这个函数判断物品是否有附加的物品,如果有,则保存原来的物品数据,暂时将物品的数据替换为附加的物品数据,然后再调用传入的计算函数,这时候计算所使用的值就是附加物品的值。当计算完毕后,又将物品的数据还原。感觉就像变魔术一样。
在UI使用上,只需要将UI的代码作为函数传到handlerAttachEquip函数中就好了,如果有第二个属性则显示第二个属性,否则就不显示。
可惜我这个做法得不到上面的认同,写完后,上面说看不懂,而且说我的代码看了他想死。。
还好我们经过漫长的讨论后,他说这次就算了,下次不能再使用这个方法。
今天发布在这里感慨一下,希望各位使用新技术的不要气馁,美好的时代会来临的。
这个属性加成涉及到类里的三个属性,value,type,grow_value,在战斗,角色属性预览,还有物品的详细信息里面都有使用到,type表示的是这个加成的类型,value表示这个加成的值,grow_value表示这个加成的成长值。现在加了一个属性,之前的计算方法就都不能用了,而且变量名字也得改,在添加后应该变成,value1,type1,grow_value1,value2,type2,grow_value2,之前所有计算的地方都需要修改,UI显示部分也需要修改。而且这些改动很多,很无脑,很繁杂。(也许有好的修改方法,知道的请在评论里面提示一下。)
上头就把这个任务给了我,然后告诉我应该这么改,就没了。我改了几个地方发现异常蛋疼,于是就想着有什么好的解决办法。学了1年多的函数式编程,现在终于被我用上了。
可以把新的属性加成看成是一个新的物品,这个物品只有3个属性value,type,grow_value,我们现在需要的是一个原来的物品附加一个新的物品,这样原来计算的方法都可以使用了,我们要做的只是再计算一次。并不是所有的物品都有两个属性,只是新加的一些物品才会有两种属性,所以再计算的时候判断一下这个物品是否有附加的物品就好了。下面用代码简单地描述一下各个类的修改,我使用的是AS3,类似JS,可以把函数作为一个对象来使用,支持闭包和匿名函数(lambda)。
第一步在原来的类里面添加三个附加的属性,以及一个attachItem
private var _attachType:int; private var _attachValue:int; private var _attachGrowValue:int; private var _attachEquipment:EquipmentData = null; //三个属性设置为只写 public function set attachType(value:int):void { _attachType = value; } public function set attachValue(value:int):void { _attachValue = value; } public function set attachGrowValue(value:int):void { _attachGrowValue = value; } //附加对象设置为只读 public function get attachEquipment():EquipmentData { if(_attachType && _attachValue && _attachGrowValue) { _attachEquipment = new EquipmentData(); _attachEquipment.value = _attachValue; _attachEquipment.valueType = _attachType; _attachEquipment.growValue = _attachGrowValue; } return _attachEquipment; }
新加的三个属性只在读表的时候用到。另外在使用这个类作为数据,并将这个类的数据进行加工后提供给外部的类中添加两个方法和一个属性。
public class CEquipment { private var _preCardXmlData:EquipmentData; public function CEquipment() { } /** * 当需要计算本装备的属性加成时将需要的计算设置为函数传入 * @param func * */ public function handleProp(func:Function):void { func(); handleAttachEquip(func); } /** * 仅针对附加属性执行的操作 * @param func * */ public function handleAttachEquip(func:Function):void { if((_cCardXmlData as EquipmentXmlData).attachEquipment) { _preCardXmlData = _cCardXmlData; _cCardXmlData = (_cCardXmlData as EquipmentData).attachEquipment; func(); _cCardXmlData = _preCardXmlData; } func = null; } public function get valueType():int { //使用_cCardXmlData 的type各种计算 } public function get value():int { //使用_cCardXmlData 的value各种计算 } public function get valueShow():String { //使用_cCardXmlData 的value和grow_value各种计算 }
说明一下第一个函数handleProp按照注释说的,可以这样修改原来调用那3个属性计算的方法。比如原来是:
switch(cEquipment.valueType) { case CardConst.ATTACK: _cEquipmentAttackMin += cEquipment.value; _cEquipmentAttackMax += cEquipment.value; break; case CardConst.DEFENSE: _cEquipmentDefenseMin += cEquipment.value; _cEquipmentDefenseMax += cEquipment.value; break; case CardConst.MINATTACKMILLI: _equipmentAttackMinMilli += cEquipment.value / 1000; break; case CardConst.MAXATTACKMILLI: _equipmentAttackMaxMilli += cEquipment.value / 1000; break; case CardConst.MINDEFENSEMILLI: _equipmentDefenseMinMilli += cEquipment.value / 1000; break; case CardConst.MAXDEFENSEMILLI: _equipmentDefenseMaxMilli += cEquipment.value / 1000; break; }
只要这样处理就好:
cEquipment.handleProp(function():void{ switch(cEquipment.valueType) { case CardConst.ATTACK: _cEquipmentAttackMin += cEquipment.value; _cEquipmentAttackMax += cEquipment.value; break; case CardConst.DEFENSE: _cEquipmentDefenseMin += cEquipment.value; _cEquipmentDefenseMax += cEquipment.value; break; case CardConst.MINATTACKMILLI: _equipmentAttackMinMilli += cEquipment.value / 1000; break; case CardConst.MAXATTACKMILLI: _equipmentAttackMaxMilli += cEquipment.value / 1000; break; case CardConst.MINDEFENSEMILLI: _equipmentDefenseMinMilli += cEquipment.value / 1000; break; case CardConst.MAXDEFENSEMILLI: _equipmentDefenseMaxMilli += cEquipment.value / 1000; break; } });
下面说明一下原理,将原来的计算过程作为一个函数传入CEquipment类中,在handleProp中立刻进行调用,这样就计算完成了第一个属性。然后handleProp将函数传给了handlerAttachEquip函数,这个函数判断物品是否有附加的物品,如果有,则保存原来的物品数据,暂时将物品的数据替换为附加的物品数据,然后再调用传入的计算函数,这时候计算所使用的值就是附加物品的值。当计算完毕后,又将物品的数据还原。感觉就像变魔术一样。
在UI使用上,只需要将UI的代码作为函数传到handlerAttachEquip函数中就好了,如果有第二个属性则显示第二个属性,否则就不显示。
可惜我这个做法得不到上面的认同,写完后,上面说看不懂,而且说我的代码看了他想死。。
还好我们经过漫长的讨论后,他说这次就算了,下次不能再使用这个方法。
今天发布在这里感慨一下,希望各位使用新技术的不要气馁,美好的时代会来临的。
相关文章推荐
- 使用Putty远程连接Linux系统遇到的问题及解决方式
- 关于控制Dcom程序使用端口的问题及解决方式
- 解决android使用gson解析json字符串,并使用混淆编译方式打包apk遇到的问题
- 使用Primose方式解决异步编程回调的一些问题--animate动画的例子
- 使用常规字符串函数及动态视图解决where in list问题(读书笔记之三)
- 11.Cocos2dx2.2下使用JNI技术调用jar包里面的一些方法遇到的一些问题及解决方式。
- 怎样使用nat和桥接方式解决虚拟机联网问题
- 解决Gitlab安装后,使用http方式推送报错的问题
- centos源码方式安装ipython2.7,setuptools、pip并解决ipython不能不能使用方向键的问题
- 安装完vs.2005之后,重新安装iis后无法使用http方式访问asp.net工程的页面的问题的解决方法
- android客户端通过Get方式提交参数给服务器,使用URL和HttpURLConnection实现,以及乱码问题解决
- PHP之Laravel框架使用问题汇总与解决方式
- 使用highcharts创建动态图表时遇到的问题及解决方式
- 安卓使用Socket发送中文,C语言服务端接收乱码问题解决方式
- SQLite使用问题解决方式
- hibernate使用hql跨表查询遇到的问题以及解决方式
- Linux 使用rpm方式安装最新mysql(5.7.16)步骤以及常见问题解决
- setinterval 使用闭包解决参数不能传递的问题
- 使用autotools工具制作Makefile过程可能出现问题与解决方式
- geotrellis使用(十七)使用缓冲区分析的方式解决单瓦片计算边缘值问题