Why
if/else 虽然简单易用,但在复杂逻辑场景下,不便于阅读和理解,同时不便于后期扩展。我们可以通过使用职责链模式+模版模式来代替 if/else。 下面通过一个例子来说明。
How
- 案例:
输入一个 1-1000 的数值 N,如果 N 是 3 或者 3 的倍数时,返回“FIZZ”;如果 N 是 5 或者 5 的倍数时, 返回“BUZZ”;既是 3 的倍数又是 5 的倍数时, 返回“FIZZBUZZ”;其他的则输出 N。
使用if/else 实现:
public String say(int input) throws Exception {
if ( input < 1 || input > 1000){
throw new Exception("Invalid input");
}
if (input % 15 == 0) {
return "FIZZBUZZ";
}
if (input % 5 == 0) {
return "BUZZ";
}
if (input % 3 == 0) {
return "FIZZ";
}
return String.valueOf(input);
}
嗅一嗅其中的坏味道,如果将来需求扩展,比如引进 7 的倍数。照此逻辑,继续添加 if,问题是解决了,但总有一天你会怀疑人生!
改进一:使用职责链模式+模版模式
public String say(int input) throws Exception {
if (input < 1 || input > 1000) {
throw new Exception("Invalid input");
}
DefaultParser defaultParser = new DefaultParser(null);
MultiOfThreeParser multiOfThreeParser = new MultiOfThreeParser(defaultParser);
MultiOfFiveParser multiFiveParser = new MultiOfFiveParser(multiOfThreeParser);
MultiOfFifteenParser fifteenPaser = new MultiOfFifteenParser(multiFiveParser);
return fifteenPaser.parse(input);
}
//---------------------------------------------------------------------
public abstract class Parser {
abstract boolean isFixedResponsibility(int inputContext);
abstract String response(int inputContext) throws Exception;
public String parse(int inputContext) throws Exception {
if (isFixedResponsibility(inputContext)) {
return response(inputContext);
}
if (nextParser != null) {
return nextParser.parse(inputContext);
}
return NULL;
}
}
public class MultiOfFifteenParser extends Parser {
public MultiOfFifteenParser(Parser nextParser) {
super(nextParser);
}
@Override
public String response(int inputContext) throws Exception {
return FLAG_FOR_MULIT_OF_FIFTEEN;
}
@Override
boolean isFixedResponsibility(int inputContext) {
return inputContext % 15 == 0;
}
}
其实上述改进还存在细微的小问题,那就是 say 方法里面的异常分支处理。怎么还存在一个 if,对于一个完美主义强迫症患者而言,它的存在就是一个灾难。继续改进一下。
- 改进二:彻底面向对象
public String say(int input) throws Exception {
DefaultParser defaultParser = new DefaultParser(null);
MultiOfThreeParser multiOfThreeParser = new MultiOfThreeParser(defaultParser);
MultiOfFiveParser multiOfFiveParser = new MultiOfFiveParser(multiOfThreeParser);
MultiOfFifteenParser FifteenPaser = new MultiOfFifteenParser(multiOfFiveParser);
InvalidNumberParser invalidNumberPaser = new InvalidNumberParser(FifteenPaser);
return invalidNumberPaser.parse(input);
}
public class InvalidNumberParser extends Parser {
public InvalidNumberParser(Parser nextParser) {
super(nextParser);
}
@Override
String response(int inputContext) throws Exception {
throw new Exception("Invalid input");
}
@Override
boolean isFixedResponsibility(int inputContext){
return (inputContext < L_THRESHOLD) || (inputContext > H_THRESHOLD);
}
}