Remove Control Flag (移除控制标记)

Summary 在一系列布尔表达式中,某个变量带有“控制标记”(control flag)的作用。break语句或return语句取代控制标记。

动机:

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

Set done to false

While not done

                If(condition)

                                Do something

                                Set done to true

                Next step of loop

这样的控制标记带来的麻烦超过了它所带来的便利。人们之所以会使用这样的控制标记,因为结构化编程原则告诉他们:每个子程序只能有一个入口和一个出口。我赞同“单一入口”原则(而且现代编程语言也强迫我们这样做),但是“单一出口”原则会让你在代码中加入讨厌的控制标记,大大降低条件表达式的可读性。这就是编程语言提供break语句和continue语句的原因:用它们跳出复杂的条件语句。去掉控制标记所产生的效果往往让你大吃一惊:条件语句真正的用途会清晰得多。

做法: 

对控制标记的处理,最显而易见的办法就是使用Java提供的break语句或continue语句。

1.找出让你跳出这段逻辑的控制标记值。

2.找出对标记变量赋值的语句,代以恰当的break语句或 continue语句。

3.每次替换后,编译并测试。

在未能提供breakcontinue语句的编程语言中,可以使用下述办法。

1.运用Extract Method,将整段逻辑提炼到一个独立函数中。

2.找出让你跳出这段逻辑的控制标记值。

3.找出对标记变量赋值的语句,代以恰当的return语句。

4.每次替换后,编译并测试。

即使在支持breakcontinue语句的编程语言中,我们也优先考虑上述第二方案。因为return语句可以非常清楚地表示:不再执行该函数中的其他任何代码。如果还有这一类代码,你早晚需要将这段代码提炼出来。

请注意标记变量是否会影响这段逻辑的最后结果。如果有影响,使用break语句之后还得保留控制标记值。如果你已经将这段逻辑提炼成一个独立函数,也可以将控制标记值放在return语句中返回。

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

    下列函数用来检查一系列人名之中是否包含两个可疑人物的名字(这两个人的名字硬编码与代码中):

void checkSecuurity(String[] people){
    boolean found = false;
    for(int i=0; i < people.length; i++){
        if(!found){
            if(people[i].equals("Don")){
                sendAlert();
                found = true;
            }
            if(people[i].equals("John")){
                sendAlert();
                found = true;
            }
        }
    }
}

这种情况下很容易找出控制标记:当变量found被赋予true时,搜索就结束。我们可以逐一引入break语句,直到替换掉所有found变量语句:

void checkSecuurity(String[] people){
    boolean found = false;
    for(int i=0; i < people.length; i++){
        if(!found){
            if(people[i].equals("Don")){
                sendAlert();
                break;
            }
            if(people[i].equals("John")){
                sendAlert();
                break;
            }
        }
    }
}

然后就可以把所有对控制标记的引用都去掉:

void checkSecuurity(String[] people){
    for(int i=0; i < people.length; i++){
        if(people[i].equals("Don")){
           sendAlert();
           break;
        }
        if(people[i].equals("John")){
            sendAlert();
            break;
        }
    }
}

范例2:以return 返回控制标记

  本项重构的另一种形式将使用return语句。为了阐述这种方法,我们把前面的例子稍加修改,以控制标记记录搜索结果:

void checkSecuurity(String[] people){
    String found = "";
    for(int i=0; i < people.length; i++){
        if(found.equals("")){
            if(people[i].equals("Don")){
                sendAlert();
                found = "Don";
            }
            if(people[i].equals("John")){
                sendAlert();
                found = "John";
            }
        }
    }
    someLaterCode(found);
}

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

void checkSecurity(String[] people){
    String found = foundMiscreant(people);
    someLaterCode(found);
}

String foundMiscreant(String[] people){
    String found = "";
    for(int i=0; i < people.length; i++){
        if(found.equals("")){
            if(people[i].equals("Don")){
                sendAlert();
                found = "Don";
            }
            if(people[i].equals("John")){
                sendAlert();
                found = "John";
            }
        }
    }
    return found;
}

  然后以return语句取代控制标记:

String foundMiscreant(String[] people){
    String found = "";
    for(int i=0; i < people.length; i++){
        if(found.equals("")){
            if(people[i].equals("Don")){
                sendAlert();
                return "Don";
            }
            if(people[i].equals("John")){
                sendAlert();
                return "John";
            }
        }
    }
    return found;
}

最后完全去掉控制标记:

String foundMiscreant(String[] people){
    for(int i=0; i < people.length; i++){
        if(found.equals("")){
            if(people[i].equals("Don")){
                sendAlert();
                return "Don";
            }
            if(people[i].equals("John")){
                sendAlert();
                return "John";
            }
        }
    }
    return "";
}

即使不需要返回某值,也可以用return语句来取代控制标记。这时候你只需要一个空的return语句就行了。

当然,如果以此办法去处理带有副作用的函数,会有一些问题。所以我们需要先以Separate Query from Modifier将函数副作用分离出去。

转载于:https://my.oschina.net/u/134516/blog/213448

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值