提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|行业资讯|编辑:龚雪|2014-10-20 09:29:54.000|阅读 208 次
概述:提高代码质量系列之:如何设计函数
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
先介绍下什么是"纯函数" 纯函数其实并没有一个很统一的定义,像Haskell的定义,就太苛刻,几乎是数学领域了,我比较认同下面这个定义:
我自己总结下,意思是一个设计良好的函数,应该就像一个黑盒子一样,你完全不需要关注函数内部的实现,你只需要关注三点, 1.函数名 2.函数接受的参数类型 3.函数返回值的类型,只要我们确定了这三 点,我们即可完全"掌控"这个函数, 我们给定一个输出,必然会返回预设的结果,这个结果不受其他任何因素的干扰. 当然,这其实是最理想的情况,"纯函数"也并非就是非黑即白的定性修饰,它更多的是一个程度上的修饰,有些函数是无论如何也不可能写成成纯函数的,比如访问非托管资源的函数. 但我们可以这样说:FunA和FunB都不是纯函数,但FunA比FunB更"纯函数"(可以类比"声明式"这个概念)。
更具体的介绍,可以看msdn里面的一个小专题 .
那么,我们为什么要写纯函数呢?因为省事省心, 直接来两段代码,
第一个函数要考虑的东西很多,比如session里面是否有值,-p2这个全局变量会不会受到其他地方的干扰,而这些其实不该是doSth应该关心的,它的职责范围被扩大了.
这两个函数,其他人或者过段时间我们自己调用的时候,谁更让人放心?
所以我们要使函数显得純.第一步就是尽可能避免全局变量,我们分析一个函数,就只分析这个函数的全部代码(有效范围)就好,如果引入了全局变量,我们分析的时候,关注范围也难免会被强制扩大到全局,同理,能声明为静态函数的,就应该避免声明为成员函数,因为成员函数可以访问对象的实例,而该对象在调用成员函数的时候,是个什么状态,有无初始化,函数是否会修改实例(引用类型)的参数,如果我们要对这个函数做重构,就难免会束手束脚.
宁愿多花一点功夫,将需要的变量在封装的纯函数中不断传递,也不要轻易将它设置为全局变量,因为在函数中传递,按照你调用的顺序,它的流程仍然是稳定的,而一旦使用全局变量,那么它就失去的约束,在哪里被人初始化了?怎么初始化的,顺序是不是按我要求的,有没有哪个地方在我做第二次初始化之前,就调用了第二次处理的功能逻辑?
再看一个例子:
以上四个函数的纯函数程度,是依次递增的,都是大家很常用的写法,那么这四个函数的区别是什么呢?
是我们调用者对函数内部实现逻辑的关注程度,依次递减,他们的功能也越来越纯粹(意味着更容易提炼和复用),调用起来也更省心,
当然,也难免会更琐碎,比如GetType3,还需要做一些具体的取值,传值,赋值操作.
其实他们也没有什么优劣之分,这之间的度,自己把握就好.
变量尽可能少: 函数内部的变量,有效范围是整个函数,如果我们在函数前面声明了10个变量,那么我们都必须时刻关注这些变量的使用情况,有些变量其实就在前面用了一次,但后来阅读的时候,你也不记得后面是不是还用到了它,所以减少变量数量,就意味着减少代码复杂度.举例:
声明尽可能晚:可能我们写类的时候养成了习惯,将变量放在最上面,统一声明,易于整理和查阅. 其实类的声明和函数的声明是不一样的,类的所有成员(变量和函数)都是无所谓先后的,而函数里面的局部变量,则是有先后顺序的,我们在不必要的地方引入了不必要的约束,也就意味着不必要的麻烦.
比如我们有一个200行代码的函数,我们在最前面声明了10个变量,这些变量是依次在函数不同部位使用的,但因为在最前面已经声明了,所以我们阅读这个函数的时候,也需要时刻注意这10个变量在函数中的使用情况, 这里我们简单的引入一个"关注度"的概念: G = 变量个数*变量的有效代码范围 ,那么这时候的总G数 = 10*200 = 2000.
而如果开始只声明2个变量,剩下的变量在使用的时候才声明,比如p3,p4是在101行代码里面声明的,那么你阅读1-100行代码的时候,就不需要关注p3,p4了(也没法关注,都还没声明呢),然后剩下6个变量在151行声明,那么现在的关注度,就只有G=2*200 +2*100 +6*50 = 900.
禁止一值多用:前面不是说要尽可能少的声明变量么,有些人就这样做:比如我声明一个state,表示Appointment的状态,用完之后,后面需要用订单状态的时候,我仍然用state字段去接值,参与新的,属于Order的业务逻辑,这个我还真见过.不过相信这种大神应该还是极少数吧.
几乎所有提到程序设计的书籍,都是推荐将函数中比较独立的业务抽取出来,放在一个新的函数中,好处很多:结构清晰,代码复用,业务解耦合.
但有时候我们的情况很尴尬,说功能独立吧,也不是特别独立,说要提公吧,其实在其他地方用的可能性也不大,但要就这样和主体业务放在一起,代码也确实显得比较乱,提公之后,又将业务逻辑分散了,这种情况应该怎么办呢?
其实我们可以选一个折中的方案:委托.
比如一个流程,需要在保存之前筛选初始数据,这个筛选的方法很大可能只在这里用(但也不排除以后再其他地方也会用,虽然可能性不大),和主体业务耦合也比较强,其实我们可以在函数中声明一个
Func<IList<Product>, AttrItemDTO, bool> FilterProduct1= (lambda Express) 或Func<IList<Product>, AttrItemDTO,int, bool> FilterProduct2= (lambda Express)
我们可以通过传递参数的形式,写成纯函数形式的FilterProduct2(第三个参数就是state),也可以写成FilterProduct1,在lambda里面直接使用前面函数中声明的"全局变量"state,
这两者都是将筛选这一流程进行了一次折中的"重构",而且花销很小, 首先它的业务逻辑还是线性顺序进行的,一条线下来,再次即使以后需要重构或者提公,也非常容易.
Ps:其实委托和lambda等函数式思维的引入,真的可以给我们带来很多新的思维启发, 不过可能是我们以前都太习惯于过程式的编码, 还需要锻炼锻炼这种新的开发理念吧.
Ps2: 关于这种函数式写法的一个非常炫酷的示例,可以参考下csdn
原文://www.cnblogs.com/suijing/p/how_to_design_method.html
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@capbkgr.cn
文章转载自:慧都控件网通过提供强大的3D CAD数据访问工具并适用于桌面、移动和Web的高级环境3D可视化发动机,HOOPS在提升造船设计和制造流程的效率方面发挥了重要作用。
HOOPS Luminate在汽车行业中的应用具有广泛的潜力和深远的影响。它通过提供高效的3D可视化、虚拟装配与拆解、性能分析、客户定制等功能,帮助汽车制造商在设计、生产和销售过程中提升效率、降低成本并提高产品质量。
在不断发展的软件开发世界中,使工具和框架与最新的平台版本保持同步至关重要,欢迎查阅~
全球航运业对国际贸易至关重要,全球 90% 以上的商品通过海运运输。准确监控和控制这些集装箱的移动对于维持高效的供应链至关重要。手动输入集装箱号码是这一程序的关键部分,它带来了相当大的挑战,例如人为错误和效率低下。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@capbkgr.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢