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
- 有一一对应关系的,使用映射表。
本帖已被设为精华帖!
//do something},'return'=>'pretty man'], 显示颜色错误