原文自工程師baeldung博客,傳送門java
可關注咱們的收藏夾,最新的翻譯文章都在這裏。git
決策結構在大多數編程語言中佔據了至爲重要的一步。可是咱們經常會被大量的那種讓代碼變得難讀且難維護的內嵌if語句搞得渾身難受。github
在此次的教程中,咱們未來過一下能夠代替內嵌if語句的各類方法。讓咱們來探索簡化咱們代碼的途徑吧。express
一般咱們會遇到一些須要作一系列條件處理的業務邏輯,而且它們每個都須要不一樣的處理。編程
爲了演示,咱們來看一下Calulator(計算器)類的一個例子。上面是帶有兩個數字類型參數,一個操做符參數以及基於操做的數值返回值的一個方法:設計模式
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語句來操做:app
public int calculateUsingSwitch(int a, int b, String operator) {
switch (operator) {
case "add":
result = a + b;
break;
// other cases
}
return result;
}
複製代碼
在典型的開發過程當中,本質上if語句會使程序變得更爲臃腫和複雜。而且,switch語句也並不是全部場景都適用,當條件複雜的時候,switch語句就沒什麼做用了。編程語言
另外一個使用嵌套條件聲明編程的影響是它使得程序變得難以管理。例如,若是咱們須要新添加一個操做,咱們須要添加一個新的if條件以及條件的實現。ide
讓咱們嘗試下使用其餘更簡潔和易管理的方法來代替這個複雜的if語句吧。學習
不少時候咱們常常碰見許多條件聲明,它們是用來處理每一個分支中類似的操做。這提供給咱們一個想法,提取一個返回具體類型的對象而且根據具體對象行爲執行操做的工廠類。
例如在下面,讓咱們定義一個帶有單獨的apply方法的操做接口
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));
}
}
複製代碼
如今在Calculator類中,咱們可以經過查詢工廠來獲取相關的操做而且應用於其中:
public int calculateUsingFactory(int a, int b, String operator) {
Operation targetOperation = OperatorFactory
.getOperation(operator)
.orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
return targetOperation.apply(a, b);
}
複製代碼
在這個例子裏,咱們能看到如何經過工廠類來將邏輯業務責任分發委託給一系列輕耦合對象當中。可是若是隻是簡單地將嵌套if語句轉移成工廠類,這明顯是不符合咱們的目的的。
做爲另外的選擇,咱們可以經過維護可以被快速查詢的對象倉庫map(映射),正如OperatorFactory#operationMap
,來達成咱們的目的。咱們也可以在運行時定義映射對象而且配置它們用於查找。
除了映射對象(map)的使用以外,咱們也可使用枚舉來標記特定的邏輯業務。在這以後,咱們能經過它來代替嵌套if語句或者swtich語句了。做爲其餘處理,咱們也可使用它們做爲對象工廠而且整理用於處理相關的業務邏輯操做。
這會減小嵌套if語句的數量而且將業務責任委託給獨立的枚舉變量中。
讓咱們來看看怎麼去實現它。首先,咱們須要定義一個枚舉類:
public enum Operator {
ADD, MULTIPLY, SUBTRACT, DIVIDE
}
複製代碼
像咱們看到這樣,這些值是不一樣操做符的標籤,而且會運用到以後的計算當中。就像嵌套if語句和switch語句那樣,咱們能夠將這些值看成選項來使用。但和它們不一樣的地方,讓咱們去設計一種可以將邏輯委託給枚舉自己的替代方法吧。
咱們爲每個枚舉量都定義了各自的方法而且進行了計算操做,例如:
ADD {
@Override
public int apply(int a, int b) {
return a + b;
}
},
// other operators
public abstract int apply(int a, int b);
複製代碼
而後在Calculator類中,咱們也定義了一個用於執行操做的方法:
public int calculate(int a, int b, Operator operator) {
return operator.apply(a, b);
}
複製代碼
如今,咱們能夠經過使用Operator#valueOf()
方法來將字符串轉換爲操做符來調用方法了:
@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
assertEquals(7, result);
}
複製代碼
在先前的討論中,咱們已經看到使用工廠類來返回指定操做符的對應的業務對象實例了,稍後,業務對象實例將用於以後的Claculator中執行計算操做。
咱們也可以設計一個Calculator#calculate
方法來接收一個能夠執行輸入的指令。這是另一種來代替嵌套if語句的方法。
首先咱們定義一個Command接口:
public interface Command {
Integer execute();
}
複製代碼
而後,讓咱們實現其中的一個AddCommand:
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();
}
複製代碼
經過實例化AddCommand對象而且將他做爲參數傳遞到Calculator#calculate
方法當中用以調用計算方法:
@Test
public void whenCalculateUsingCommand_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(new AddCommand(3, 7));
assertEquals(10, result);
}
複製代碼
當咱們最終編寫了大量的嵌套if語句時,每個條件都描述了特定的業務規則,用於評估正確邏輯操做的執行。規則引擎將這些複雜的草從主代碼中去掉。規則引擎是用於評估規則而且基於輸入返回結果。
讓咱們經過設計一個簡單的規則引擎來作下試驗。這個引擎是經過一組規則來處理表達式,並從選中的規則返回結果。首先,咱們定義一個規則接口:
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();
}
}
複製代碼
這個規則引擎接收一個表達式而且返回Result。如今,咱們設計一個帶有兩個數值變量以及一個用於操做的Operator對象的表達式(Expression)類:
public class Expression {
private Integer x;
private Integer y;
private Operator operator;
}
複製代碼
最後,咱們定義一個AddRule類,它只在加操做中使用到:
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;
}
}
複製代碼
如今,咱們可以使用Expression來調用RuleEngine了:
@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());
}
複製代碼
在此次教程中,咱們探索了一系列不一樣的方法來簡化複雜的代碼。同時咱們也學到了這麼去使用有效的設計模式來取代繁雜的嵌套fi聲明語句。
一如既往,讀者們能夠在咱們的github倉庫中獲取到完整的源碼。
咱們下期見。
想必你們之前或多或少都會被這種無止境的if語句所困擾,這篇文章中做者介紹了4種方法用來取代原先維護成本極高的if結構,但願看了之後對你們以後的結構設計思路有所幫助,避免出現讓別人叫慘的if地獄。
小喇叭
廣州蘆葦科技Java開發團隊
蘆葦科技-廣州專業互聯網軟件服務公司
抓住每一處細節 ,創造每個美好
關注咱們的公衆號,瞭解更多
想和咱們一塊兒奮鬥嗎?lagou搜索「 蘆葦科技 」或者投放簡歷到 server@talkmoney.cn 加入咱們吧
關注咱們,你的評論和點贊對咱們最大的支持