一般而言,我们写if-else是为了异常情况处理和不同状态处理,举栗说明:
//异常情况处理
$obj = new Object();
if( $obj === null )
{
//do something
}
else
{
//do something
}
//不同状态处理
$obj = new Object();
if( $obj->getType() == 1 )
{
//do something
}
elseif( $obj->getType() == 2 )
{
//do something
}
else
{
//do something
}
第一个例子中,if里面是出错处理流程,else里面是正常业务逻辑,属于代码健壮性判断;
第二个例子中,无论哪个情况都属于正常的业务逻辑。
太多的if-else结构会导致逻辑复杂,易读性差,维护也就差,也就容易引发bug。
重构if-else的原则:尽可能维持正常流程代码在最外层。 即尽量保持主干代码是正常流程,避免嵌套过深。
手段有:减少嵌套、移除临时变量、条件取反判断、合并条件表达式等。
减少嵌套
//重构前
function test()
{
if( A )
{
$result = 1;
}
else
{
if( B )
{
$result = 2;
}
else
{
if( C )
{
$result = 3;
}
else
{
$result = 4;
}
}
}
return $result;
}
//重构后
function test()
{
if( A )
{
return 1;
}
if( B )
{
return 2;
}
if( C )
{
return 3;
}
return 4;
}
重构后首先减少了嵌套,逻辑清晰易读性高,其次是去除了$result临时变量,直接return返回,减少了代码执行流程。
条件取反判断
//重构前
function test()
{
$result = 0;
if( A )
{
if( B && C )
{
$result = Income / Duration * Ratio;
}
}
return $result;
}
//第一轮重构后
function test()
{
if( !A )
{
return 0;
}
if( B && C )
{
return Income / Duration * Ratio;
}
return 0;
}
//本轮重构移除了临时变量,也减少了嵌套
//第二轮重构后
function test()
{
if( !A || !B || !C )
{
return 0;
}
return Income / Duration * Ratio;
}
将条件取反使异常情况先退出,让正常流程保持在主流程。
合并条件表达式
//重构前
function test()
{
if( A )
{
return 0;
}
if( B )
{
return 0;
}
if( C )
{
return 0;
}
//do something
}
//重构后
function test()
{
if( A || B || C )
{
return 0;
}
//do something
}
这种方式简单粗暴且效果明显。
封装方法
//重构前
function test()
{
$obj = new MyObj();
$money = 0;
if( $obj->getType() == 1 )
{
$objA = $obj->getObjA();
$money = $objA->getMoney() * $obj->getRate();
}
elseif( $obj->getType() == 2 )
{
$objB = $obj->getObjB();
$money = $objB->getMoney() * $obj->getRate() + 1000;
}
}
//重构后
function test()
{
$obj = new MyObj();
if( $obj->getType() == 1 )
{
return getType1Money( $obj );
}
elseif( $obj->getType() == 2 )
{
return getType2Money( $obj );
}
return 0;
}
function getType1Money( $obj )
{
$objA = $obj->getObjA();
return $objA->getMoney() * $obj->getRate();
}
function getType2Money( $obj )
{
$objB = $obj->getObjB();
return $objB->getMoney() * $obj->getRate() + 1000;
}
把if-else里的代码封装成函数,函数的好处是屏蔽内部实现,缩短了if-else分支的代码,逻辑更清晰,能一眼看出每个条件内的功能。
多态
//重构前
function test()
{
switch( Type )
{
case 'Cat' :
return 'Meow~';
case 'Dog' :
return 'Bark~';
case 'Duck' :
return 'Quack~';
}
}
//重构后
abstract Class Animal
{
public abstract function sound();
}
Class Cat extends Animal
{
public function sound()
{
return 'Meow~';
}
}
Class Dog extends Animal
{
public function sound()
{
return 'Bark~';
}
}
Class Duck extends Animal
{
public function sound()
{
return 'Quack~';
}
}
使用多态后直接没有了 if-else,但使用多态对原来代码修改过大,需要一番功夫才行。最好在设计之初就使用多态方式。