在我們平時的開發過程中,經常可能會出現大量If else的場景,代碼顯的很臃腫,非常不優雅。那我們又沒有辦法處理呢?
針對大量的if嵌套讓代碼的複雜性增高而且難以維護。本文將介紹多種解決方案。
案例
下面模擬業務邏輯,根據傳入的條件作出不同的處理方式。
拿一個計算器類當做案例,有加減乘除四種方法,輸出結果和四種操作有關。
public int calculate(int a, int b, String operator) {
int result = Integer.MIN_VALUE;
if ("add".equals(operator)) {
result = a + b;
} else if ("multiply".equals(operator)) {
result = a * b;
} else if ("divide".equals(operator)) {
result = a / b;
} else if ("subtract".equals(operator)) {
result = a - b;
}
return result;
}
當然也可以用switch來實現。
public int calculateUsingSwitch(int a, int b, String operator) {
switch (operator) {
case "add":
result = a + b;
break;
// other cases
}
return result;
}
隨着條件越來越多,複雜性也增高,也越來越難以維護。
重構
1、工廠類我們將操作進行抽象給出一個操作接口
public interface Operation {
int apply(int a, int b);
}
然後實現加減乘除四個方法
public class Addition implements Operation {
@Override
public int apply(int a, int b) {
return a + b;
}
}
然後通過操作工廠提供操作
public class OperatorFactory {
static Map<String, Operation> operationMap = new HashMap<>();
static {
operationMap.put("add", new Addition());
operationMap.put("divide", new Division());
// more operators
}
public static Optional<Operation> getOperation(String operator) {
return Optional.ofNullable(operationMap.get(operator));
}
}
調用
public int calculateUsingFactory(int a, int b, String operator) {
Operation targetOperation = OperatorFactory
.getOperation(operator)
.orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
return targetOperation.apply(a, b);
}
新增操作只需要維護操作工廠的operationMap即可。
2、使用枚舉
在枚舉中定義操作,如下:
public enum Operator {
ADD, MULTIPLY, SUBTRACT, DIVIDE
}
然而不同的操作對應的邏輯不一樣,我們編寫抽象方法
ADD {
@Override
public int apply(int a, int b) {
return a + b;
}
},
// other operators
public abstract int apply(int a, int b);
調用時直接傳入枚舉值
public int calculate(int a, int b, Operator operator) {
return operator.apply(a, b);
}
@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
assertEquals(7, result);
}
3、命令模式
定義命令接口。
public interface Command {
Integer execute();
}
實現加法
public class AddCommand implements Command {
// Instance variables
public AddCommand(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public Integer execute() {
return a + b;
}
}
定義一個Calculator類,加入執行命令的方法。
public int calculate(Command command) {
return command.execute();
}
測試代碼
@Test
public void whenCalculateUsingCommand_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(new AddCommand(3, 7));
assertEquals(10, result);
}
4、規則引擎
定義規則接口
public interface Rule {
boolean evaluate(Expression expression);
Result getResult();
}
實現規則引擎
public class RuleEngine {
private static List<Rule> rules = new ArrayList<>();
static {
rules.add(new AddRule());
}
public Result process(Expression expression) {
Rule rule = rules.stream()
.filter(r -> r.evaluate(expression))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule"));
return rule.getResult();
}
}
定義表達式
public class Expression {
private Integer x;
private Integer y;
private Operator operator;
}
定義加法規則
public class AddRule implements Rule {
@Override
public boolean evaluate(Expression expression) {
boolean evalResult = false;
if (expression.getOperator() == Operator.ADD) {
this.result = expression.getX() + expression.getY();
evalResult = true;
}
return evalResult;
}
}
給規則引擎傳入表達式來調用
@Test
public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() {
Expression expression = new Expression(5, 5, Operator.ADD);
RuleEngine engine = new RuleEngine();
Result result = engine.process(expression);
assertNotNull(result);
assertEquals(10, result.getValue());
}
總結雖然說常見的代碼中if...else不可避免,但濫用 if...else 會對代碼的可讀性、可維護性造成很大傷害。因此,使用好 if...else,讓代碼清爽對於你的項目長遠考慮有十分重要的意義。
英文原文:https://www.baeldung.com/java-replace-if-statements
其他參考資料:
策略設計模式:http://www.runoob.com/design-pattern/strategy-pattern.html
命令設計模式:http://www.runoob.com/design-pattern/command-pattern.html
推薦閱讀:
掃碼關注公衆號,發送關鍵詞獲取相關資料:
-
發“Springboot”領取電商項目實戰源碼;
-
發“SpringCloud”領取學習實戰資料;