您的位置:首页 > 其它

重构手法之简化条件表达式【2】

2017-11-27 08:59 190 查看

返回总目录

本小节目录

3Consolidate Duplicate Conditional Fragments(合并重复的条件片段)

概要

在条件表达式的每个分支上有着相同的一段代码。

将这段重复代码搬到条件表达式之外。

动机

如果有一组条件表达式的所有分支都执行了相同的某段代码,将这段代码搬移到条件表达式外面。这样才能更清楚地表明哪些东西随条件的变化而变化、哪些东西保持不变。

范例

假如有如下代码:

class Deal
{
public double Price { get; set; }
private bool IsSpecialDeal()
{
//your code here
return true;
}

private void Send()
{
//your code here
}

public double GetTotalPrice()
{
double total;
if (IsSpecialDeal())
{
total = Price * 0.95;
Send();
}
else
{
total = Price * 0.98;
Send();
}
return total;
}
}

由于条件表达式的两个分支都执行了Send()函数,所以将其移到条件表达式的外围:

class Deal
{
public double Price { get; set; }
private bool IsSpecialDeal()
{
//your code here
return true;
}

private void Send()
{
//your code here
}

public double GetTotalPrice()
{
double total;
if (IsSpecialDeal())
{
total = Price * 0.95;
}
else
{
total = Price * 0.98;
}
Send();
return total;
}
}

这样的重构手法同时也可以避免重复代码。

小结

我们在对待异常时,也是这样做的。如果try块和catch块内都重复执行了同一段代码,可以将其移到finally块内。

4Remove Control Flag(移除控制标记)

概要

在一系列布尔表达式中,某个变量带着“控制标记”(control flag)的作用。

以break语句或return语句取代控制标记。

动机

在一系列条件表达式中,常常会看到用以判断何时停止条件检查的控制标记:

set done to false

while not done

  if(condition)

    do something

    set done to true

  next step of loop

这样的控制标记大大降低了条件表达式的可读性。以break语句或return语句取代控制标记,会带来很大的便利。

范例:以break取代简单的控制标记

下列函数用来检查一系列人名之中是否包含两个可疑人物的名字:

class Person
{
public void CheckSecurity(string[] people)
{
bool found = false;
foreach (var person in people)
{
if (!found)
{
if (person == "Don")
{
SendAlert();
found = true;
}
if (person == "John")
{
SendAlert();
found = true;
}
}
}
}

private void SendAlert()
{

}
}

这种情况下很容易找出控制标记:当变量found被赋予true时,搜索就结束。这样我们可以引入break语句替换掉对found变量赋值的语句,替换完成后删除控制标记的引用:

class Person
{
public void CheckSecurity(string[] people)
{
foreach (var person in people)
{
if (person == "Don")
{
SendAlert();
break;
}
if (person == "John")
{
SendAlert();
break;
}
}
}

private void SendAlert()
{

}
}

范例:以return返回控制标记

我们将上面的例子稍微改动下:

class Person
{
public void CheckSecurity(string[] people)
{
string found = string.Empty;
foreach (var person in people)
{
if (found == string.Empty)
{
if (person == "Don")
{
SendAlert();
found = "Don";
}
if (person == "John")
{
SendAlert();
found = "John";
}
}
}
OtherMethod(found);
}

private void SendAlert()
{

}

private void OtherMethod(string found)
{

}
}

在这里,变量found做了两件事:既是控制标记,也是运算结果。遇到这种情况,一般都是先把计算found变量的代码提炼到一个独立函数中:

class Person
{
public void CheckSecurity(string[] people)
{
string found = FoundMiscreant(people);
OtherMethod(found);
}

private string FoundMiscreant(string[] people)
{
string found = string.Empty;
foreach (var person in people)
{
if (person == "Don")
{
SendAlert();
found = "Don";
}
if (person == "John")
{
SendAlert();
found = "John";
}
}
return found;
}
private void SendAlert()
{

}

private void OtherMethod(string found)
{

}
}

然后以return语句取代控制语句,并且完全去掉控制标记:

class Person
{
public void CheckSecurity(string[] people)
{
string found = FoundMiscreant(people);
OtherMethod(found);
}

private string FoundMiscreant(string[] people)
{
foreach (var person in people)
{
if (person == "Don")
{
SendAlert();
return "Don";
}
if (person == "John")
{
SendAlert();
return "John";
}
}
return string.Empty;
}
private void SendAlert()
{

}

private void OtherMethod(string found)
{

}
}

如果返回值是void,也可以用return语句取代控制标记,只不过是一个空的return。

小结

如果以此办法去处理带有副作用的函数,需要先将查询函数和修改函数分离。

 

To Be Continued……

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: