关闭

提高代码质量:如何编写函数

发表于:2016-3-04 11:24

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:狼狼的蓝胖子    来源:51Testing软件测试网采编

  尽量不要使用bool类型作为参数
  有的时候,我们会写出使用bool作为参数的情况,比如:
  1 var getProduct = function(finished) {
  2     if(finished){
  3     }
  4     else{
  5     }
  6 }
  7
  8 // 调用
  9 getProduct(true);
  如果没有注释,使用者看到这样的代码:getProduct(true),他肯定搞不清楚true是代表什么意思,还要去查看函数定义才能明白这个函数是如何使用的。这就意味着这个函数不够清晰,就应该考虑去优化它。通常有两种方式去优化它:
  (1)将函数一分为二,分成两个函数getFinishedProduct和getUnFinishedProduct
  (2)将bool转换成有意义的枚举getProduct(ProductStatus)
  不要修改输入参数
  如果输入参数在函数内被修改了,很有可能造成潜在的bug,而且使用者不知道调用函数后居然会修改函数参数。
  正确使用输入参数的做法应该是只传入参数用于函数调用。
  如果不可避免地要修改,一定要在注释中说明。
  尽量不要使用输出参数
  使用输出参数说明这个函数不只做了一件事情,而且使用者使用的时候可能还会感到困惑。正确的方式应该是分解函数,让函数只做一件事。
  编写函数体
  函数体就是实现函数功能的整个逻辑,是一个函数最关键的地方。下面我谈谈关于函数代码编写的一些个人想法。
  相关操作放在一起
  有的时候,我们会在一个函数内进行一系列的操作来完成一个功能,比如:
  1 var calculateTotalPrice = function()  {
  2     var roomCount = getRoomCount();
  3     var mealCount = getMealCount();
  4
  5     var roomPrice = getRoomPrice(roomCount);
  6     var mealPrice = getMealPrice(mealCount);
  7
  8     return roomPrice + mealPrice;
  9 }
  这段代码计算了房间价格和早餐价格,然后将两者相加返回总价格。
  这段代码乍一看,没有什么问题,但是我们分析代码,我们先是分别获取了房间数量和早餐数量,然后再通过房间数量和早餐数量分别计算两者的价格。这种情况下,房间数量和计算房间价格的代码分散在了两个位置,早餐价格的计算也是分散到了两个位置。也就是两部分相关的代码分散在了各处,这样阅读起代码来逻辑会略显不通,代码组织不够好。我们应该让相关的语句和操作放在一起,也有利于重构代码。我们修改如下:
  1 var calculateTotalPrice = function()  {
  2     var roomCount = getRoomCount();
  3     var roomPrice = getRoomPrice(roomCount);
  4
  5     var mealCount = getMealCount();
  6     var mealPrice = getMealPrice(mealCount);
  7
  8     return roomPrice + mealPrice;
  9 }
  我们将相关的操作放在一起,这样代码看起来更清晰了,而且也更容易重构了。
  尽量减少代码嵌套
  我们平时写if,switch或for语句是常有的事儿,也一定写过多层if或for语句嵌套的情况,如果代码里的嵌套超过3层,阅读起来就会非常困难了。我们应该尽量避免代码嵌套多层,最好不要超过2层。下面我来说说我平时一些减少嵌套的技巧或方法。
  if语句嵌套的问题
  多层if语句嵌套是常有的事情,有什么好的方法可以减少嵌套呢?
  1、尽早终止函数或返回数据
  如果符合某个条件下可以直接终止函数,则应该将这个条件放在第一位。我们来看看下面的例子。
  1 if(condition1) {
  2     if(condition2){
  3         if(condition3){
  4         }
  5         else{
  6             return;
  7         }
  8     }
  9     else{
  10         return;
  11     }
  12 }
  13 else {
  14     return;
  15 }
  这段代码中if语句嵌套了3层,看起来已经很复杂了,我们可以将最后面的return提取到最前面去。
  1 if(!condition1){
  2     return;
  3 }
  4 if(!condition2){
  5     return;
  6 }
  7 if(!condition3){
  8     return;
  9 }
  10 //doSth
  这段代码中,我们把condition1等于false的语句提取到前面,直接终止函数,将多层嵌套的if语句重构成只有一层if语句,代码也更清晰了。
  注意:一般情况下,我们写if语句会将条件为true的情况写在前面,这也比较符合我们的思维习惯。如果是多层嵌套的情况,应该优先减少if语句的嵌套
  2、不适用if语句或switch语句
  条件语句一般来说是不可避免的,有的时候,我们要判断很多条件就会写很多if-elseif语句,嵌套的话,就更加麻烦了。如果有一天增加了新需求,我们就要去增加一个if分支语句,这样不仅修改起来麻烦,而且容易出错。《代码大全》提出的表驱动法可以有效地解决if语句带来的问题。我们来看下面这个例子:
  1 if(condition == “case1”){
  2     return 1;
  3 }
  4 elseif(condition == “case2”){
  5     return 2;
  6 }
  7 elseif(condition == “case3”){
  8     return 3;
  9 }
  10 elseif(condition == “case4”){
  11     return 4;
  12 }
  这段代码分别依次判断了四种情况,如果再增加一种情况,我们就要再新增一个if分支,这样就可能造成潜在的问题,如何去优化这段代码呢?我们可以采用一个Map或Dictionary来将每一种情况和相应值一一对应。
  1 var map = {
  2     "case1":1,
  3     "case2":2,
  4     "case3":3,
  5     "case4":4
  6 }
  7 return map[condition];
  通过map优化后,整个代码不仅更加简洁,修改起来也更方便而且不易出错了。
  当然,很多时候我们的条件判断语句并不是这么简单的,可能会涉及到复杂的逻辑运算,大家可以查看《代码大全》第18章,其中有详细的介绍。
  3、提取内层嵌套为一个函数进行调用
  多层嵌套的时候,我们还可以将内层嵌套提取到一个新的函数中,然后调用该函数,这样代码也就更清晰了。
  for循环嵌套优化
  for循环嵌套相比于if嵌套来说更加复杂,阅读起来会更麻烦,下面说说几点要注意的东西:
  1、最多只能两层for循环嵌套
  2、提取内层循环到新函数中
  3、多层循环时,不要简单地位索引变量命名为i,j,k等,容易造成混淆,要有具体的意思
  提取复杂逻辑,语义化
  有的时候,我们会写出一些比较复杂的逻辑,阅读代码的人看到后可能搞不清楚要做什么,这个时候,就应该提取出这段复杂的逻辑代码。
  1 if (age > 18 && gender == "man") {
  2     //doSth
  3 }
  这段代码表示当年龄大于18并且是男性的话,可以doSth,但是还是不够清晰,可以将其提取出来
  1 var canDoSth = function (age, gender){
  2     return age > 18 && gender == "man";
  3 }
  4 ...
  5 ...
  6 ...
  7 if(canDoSth(age, gender)){
  8     //doSth
  9 }
  虽说多了一个函数,但是代码更加清晰和语义化了。
  总结
  本文从函数命名,函数参数和函数的代码编写三个方面谈了关于如何编写好一个函数的感受和想法。文中提到了很多具体的情况,当然日常编码中肯定会遇到更多复杂的情况可能我暂时没有想到。我简单的归纳了几点:
  1、准确地对变量、函数命名
  2、不要有重复逻辑的代码
  3、函数的行数不要超过20行,这里的20行只是个大概,并不一定是这个数字
  4、减少嵌套
  我相信大家一定会很多关于这方面的经验,欢迎进行交流,共同提高代码质量。
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号