程序中减少使用if语句的方法集锦
作者:网络转载 发布时间:[ 2016/7/15 10:26:18 ] 推荐标签:测试开发技术 程序
大约十年前,我听说了反if的活动,觉得这个概念非常荒谬。如果不用if语句,又怎么能写出有用的程序呢?这简直太荒谬了。
但之后你会开始思考:是否还记得上周你拼命想读懂的深度嵌套代码?糟透了对么?要是有办法能简化它该多好。
反if活动的网站上没给出多少实用性建议,因此在本文中,作者将会提供一系列模式,也许你会用得上。但首先我们来关注一下if语句到底造成了什么问题。

if语句的问题
if语句的第一个问题在于,通常出现if语句的代码很容易越改越糟。我们试着写个新的if语句:
public void theProblem(boolean someCondition) {
// SharedState
if(someCondition) {
// CodeBlockA
} else {
// CodeBlockB
}
}
这时候还不算太糟,但已经存在一些问题了。在阅读这段代码时,我必须得去查看对同一个SharedState来说,CodeBlockA和CodeBlockB有什么改动。开始这段代码很容易阅读,但随着CodeBlock越来越多,耦合越来越复杂之后,会很难读。
上面这种CodeBlock进一步嵌套if语句与本地return的滥用情况也很常见,很难搞懂业务逻辑是选择了哪种路径。
if语句的第二个问题在于:复制时会有问题,也是说,if语句缺失domain的概念。很容易由于在不需要的情况下,由于将内容放在一起而增加耦合性,造成代码难读难改。
而第三个问题在于:开发者必须在头脑中模拟执行实现情况——你得让自己变成一台小型电脑,从而造成脑细胞浪费。开发者的精力应当用来思考如何解决问题,而不是浪费在如何将复杂的代码分支结构编织在一起之上。
虽然想要直截了当地写出替代方案,但首先我得强调这句话:
凡事中庸而行,尤其是中庸本身
if语句通常会让代码更加复杂,但这不代表我们要完全抛弃if语句。我曾经看到过一些非常糟糕的代码,只是为了消除所有的if语句而刻意避开if语句。我们想要绕开这个误区,
下面我给出的每种模式,都会给出使用范围。
单独的if语句如果不复制到其他地方,也许是不错的句子。在复制if语句时,我们会希望预知危险的第六感起效。
在代码库之外,在与危险的外部世界交流时,我们会想要验证incoming response,并根据其作出相应的修改。但在自己的代码库中,由于有可靠的gatekeeper把关,我觉得这是个很好的机会,我们可以尝试使用简单、更为丰富与强大的替代方案来实现。
模式1:布尔参数(Boolean Params)
背景: 有方法在修改行为时使用了boolean。
public void example() {
FileUtils.createFile("name.txt", "file contents", false);
FileUtils.createFile("name_temp.txt", "file contents", true);
}
public class FileUtils {
public static void createFile(String name, String contents, boolean temporary) {
if(temporary) {
// save temp file
} else {
// save permanent file
}
}
}
问题: 在看到这段代码时,实际上你是将两个方法捆绑到一起,布尔参数的出现让你有机会在代码中定义一个概念。
适用范围: 通常看到这种情况,如果在编译时我们可以算出代码要采用哪种路径,可以放心使用这种模式。
解决方案: 将这个方法拆分成两个新的方法,然后if不见了。
public void example() {
FileUtils.createFile("name.txt", "file contents");
FileUtils.createTemporaryFile("name_temp.txt", "file contents");
}
public class FileUtils {
public static void createFile(String name, String contents) {
// save permanent file
}
public static void createTemporaryFile(String name, String contents) {
// save temp file
}
}
模式2:使用多态(Polymorphism)
背景: 根据类型switch时。
public class Bird {
private enum Species {
EUROPEAN, AFRICAN, NORWEGIAN_BLUE;
}
private boolean isNailed;
private Species type;
public double getSpeed() {
switch (type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor();
case NORWEGIAN_BLUE:
return isNailed ? 0 : getBaseSpeed();
default:
return 0;
}
}
private double getLoadFactor() {
return 3;
}
private double getBaseSpeed() {
return 10;
}
}
问题: 在添加新的类型时,我们必须要记得更新switch语句,此外随着不同bird的概念添加进来,bird类的凝聚力越来越糟。

sales@spasvo.com