if else 重构经验谈

我也来尝试回答这个问题如果程序中出现多层嵌套的 if...else...语句,如何重构可使程序逻辑变得更为清晰易读?

一般原则是if 是越少越好,能不用就不用,层级越少越好。

技巧1:映射表法

function contry_initial($country){
    if ($country==="China" ){
       return "CHN";
    }else if($country==="America"){
       return "USA";
    }else if($country==="Japna"){
      return "JPN";
    }else{
       return "OTHER";
    }
}

这样的if语句,可以看到值和返回是一一对应的,所以你可以这样写

function contry_initial($country){
  $countryList=[
      "China"=> "CHN",
      "America"=> "USA",
      "Japna"=> "JPN",
    ];

    if(in_array($country, array_keys($countryList))) {
        return $countryList[$country];
    }
    return "Other";

}

如果需要更加自由的定义映射表的话,可以这样写

function contry_initial($country, array $countryList){
    if(in_array($country, array_keys($countryList))) {
        return $countryList[$country];
    }
    return "Other";
}

完全去掉if语句可以写成

function contry_initial($country, array $countryList){
    return in_array($country, array_keys($countryList))?$countryList[$country]:"Other";
}

技巧二:多维映射表

自己制定一个标准,建立一个多维的映射表,然后尽量少的if语句去囊括所有范例

function match($age,$gender,$pretty){
$list=[
      ['age'=>[1,12], 'gender'=>"Male",'pretty'=>true,'action'=>function(){//do something},'return'=>'pretty young  man'],
      ['age'=>[1,12], 'gender'=>"Female",'pretty'=>true,'action'=>function(){//do something},'return'=>'pretty young lady'],
      ['age'=>[1,12], 'gender'=>"Male", 'pretty'=>false,'action'=>function(){//do something},'return'=>'boy'],
      ['age'=>[1,12], 'gender'=>"Female",'pretty'=>false,'action'=>function(){//do something},'return'=>'girl'],
      ['age'=>[13,18], 'gender'=>"Male", 'pretty'=>true,'action'=>function(){//do something},'return'=>'pretty man'],
....
   ];

    foreach($list as $item){
       if($age>=$item['age'][0]&&$age<=$item['age'][1]&&$gender===$item['gender']&&$pretty===$item['pretty']){
            $item['action']();
          return $item['return'];

       }
    }
      return null;

}

当然,这样排列组合可能会有很多案例,而callable的代码也会有重复。所以改进的方案是

function match($age,$gender,$pretty){
    $ageList=[
        [ "age"=>[1,12],"action"=>function(){},"return"=>"young"],
        [ "age"=>[13,18],"action"=>function(){},"return"=>"teenage"],
        [ "age"=>[19,100],"action"=>function(){},"return"=>"adult"],
        [ "age"=>[100,1000],"action"=>function(){},"return"=>"adult"],
    ];

    $genderList=[
        'Male'=>["action"=>function(){},"return"=>"man"],
        'Female'=>["action"=>function(){},"return"=>"lady"],
        'default'=>["action"=>function(){},"return"=>"person"],
    ];

    $prettyList=[
        true=>["action"=>function(){},"return"=>"pretty"],
        false=>["action"=>function(){},"return"=>""],
    ];

    foreach($ageList as $item){
        if($age>=$item['age'][0]&&$age<=$item['age'][1]){
            $item['action']();
            $returnValue=    $item['return'];
        }
    }

     if(in_array($gender,array_keys($genderList))) {
        $genderList[$gender]['action']();
        $returnValue .=" ".$genderList[$gender]['return'];
    } else {
        $genderList['default']['action']();
        $returnValue .=" ".$genderList['default']['return'];
    }

    $prettyList[$pretty]['action']();

    return   $prettyList[$pretty]['return']." ".$returnValue;
}

总结

以上代码并不完美,总之要更具需要去重构,而不是为了优雅而重构。

使用映射表法的好处是提高单元测试的覆盖率,而坏处是增加了加载时间和消耗内存空间

当然,还是要注意一些

  • return能越早越好
  • if else 语句越少越好,可以用condition?a:b 表达的,就不要用if else
  • 有一一对应关系的,使用映射表。
本帖已被设为精华帖!
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 1

//do something},'return'=>'pretty man'], 显示颜色错误

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!