重构条件-Remove Control Flag移除控制标记四
创始人
2025-06-01 15:56:59

重构条件-Remove Control Flag移除控制标记四

1.移除控制标记

1.1.使用场景

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

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

// 条件标记set done to falsewhile not doneif (condition)do somethingset done to truenext step of loop

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

1.2.如何做

  • 对控制标记的处理,最显而易见的办法就是使用Java提供的break语句或continue语句。
  • 找出让你跳出这段逻辑的控制标记值。
  • 找出对标记变量赋值的语句,代以恰当的break语句或continue语句。
  • 每次替换后,编译并测试。
  • 在未能提供break和continue语句的编程语言中,可以使用下述办法。
  • 运用Extract Method (110),将整段逻辑提炼到一个独立函数中。
  • 找出让你跳出这段逻辑的控制标记值。
  • 找出对标记变量赋值的语句,代以恰当的return语句。
  • 每次替换后,编译并测试。
  • 即使在支持break和continue语句的编程语言中,我通常也优先考虑上述第二种方案。因为return语句可以非常清楚地表示:不再执行该函数中的其他任何代码。如果还有这一类代码,你早晚需要将这段代码提炼出来。
  • 请注意标记变量是否会影响这段逻辑的最后结果。如果有影响,使用break语句之后还得保留控制标记值。如果你已经将这段逻辑提炼成一个独立函数,也可以将控制标记值放在return语句中返回。

1.3.示例

1.以break 取代简单的控制标记

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

  void checkSecurity(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语句

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

直到替换掉所有对found变量赋值的语句

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

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

void checkSecurity(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 checkSecurity(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";}}}// found值作为参数someLaterCode(found);}

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

  void checkSecurity(String[] people) {String found = foundMiscreant(people);someLaterCode(found);}// 将计算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();found = "John";}}}return found;}

最后完全去掉控制标记

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

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

当然,如果以此办法去处理带有副作用的函数,会有一些问题。所以我需要先以Separate Query from Modifier (279)将函数副作用分离出去。稍后你会看到这方面的例子。

相关内容

热门资讯

原创 1... 根据环球网报道,前不久,以色列军方发表声明称打击了叙利亚政权位于大马士革军事总部的入口。这是以伊冲突...
原创 杨... 北京时间7月18日,2025年NBA拉斯维加斯夏季联赛继续进行,今天的一场焦点比赛是波特兰开拓者迎战...
我来教教您“湖北休闲有挂吗”[... 您好:湖北休闲这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
玩家分享攻略“天酷牛牛可以开挂... 您好:天酷牛牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信【9752949】很多玩家在这款游戏...
科技推荐“九九麻将可以开挂吗”... 您好:九九麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...