java重构ifelse_常见重构技巧-5种⽅式去除多余的ifelse
常见重构技巧 - 去除多余的if else
最为常见的是代码中使⽤很多的if/else,或者switch/case;如何重构呢?⽅法特别多,本⽂带你学习其中的技巧。
出现if/else和switch/case的场景
通常业务代码会包含这样的逻辑:每种条件下会有不同的处理逻辑。⽐如两个数a和b之间可以通过不同的操作符(+,-,*,/)进⾏计算,初学者通常会这么写:
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/case:
public int calculateUsingSwitch(int a, int b, String operator) {
switch (operator) {
case "add":
result = a + b;
break;
// other cases
}
return result;
}
这种最基础的代码如何重构呢?
重构思路
有⾮常多的重构⽅法来解决这个问题, 这⾥会列举很多⽅法,在实际应⽤中可能会根据场景进⾏⼀些调整;另外不要纠结这些例⼦中显⽽易见的缺陷(⽐如没⽤常量,没考虑多线程等等),⽽是把重⼼放在学习其中的思路上。@pdai
⽅式⼀ - ⼯⼚类
定义⼀个操作接⼝
public interface Operation {
int apply(int a, int b);
}
实现操作, 这⾥只以add为例
public class Addition implements Operation {
@Override
public int apply(int a, int b) {
return a + b;
}
}
实现操作⼯⼚
public class OperatorFactory {
static Map operationMap = new HashMap<>();
static {
operationMap.put("add", new Addition());
operationMap.put("divide", new Division());
// more operators
}
public static Optional getOperation(String operator) {
return Optional.(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);
}
对于上⾯为什么⽅法名是apply,Optional怎么⽤? 请参考这篇:
Java 8 - 函数编程(lambda表达式)
Lambda 表达式的特点?
Lambda 表达式使⽤和Stream下的接⼝?
函数接⼝定义和使⽤,四⼤内置函数接⼝Consumer,Function,Supplier, Predicate.
Comparator排序为例贯穿所有知识点。
Java 8 - Optional类深度解析
Optional类的意义?
Optional类有哪些常⽤的⽅法?
Optional举例贯穿所有知识点
如何解决多重类嵌套Null值判断?
⽅式⼆ - 枚举
枚举适合类型固定,可枚举的情况,⽐如这的操作符; 同时枚举中是可以提供⽅法实现的,这就是我们可以通过枚举进⾏重构的原因。定义操作符枚举
public enum Operator {
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);
}
写个测试⽤例测试下:
@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
assertEquals(7, result);
}
看是否很简单?
⽅法三 - 命令模式
java switch case string
命令模式也是⾮常常⽤的重构⽅式, 把每个操作符当作⼀个Command。
测试⽤例
@Test
public void whenCalculateUsingCommand_thenReturnCorrectResult() {
Calculator calculator = new Calculator();
int result = calculator.calculate(new AddCommand(3, 7));
assertEquals(10, result);
}
注意,这⾥new AddCommand(3, 7)仍然没有解决动态获取操作符问题,所以通常来说可以结合简单⼯⼚模式来调⽤:
创建型 - 简单⼯⼚(Simple Factory)
简单⼯⼚(Simple Factory),它把实例化的操作单独放到⼀个类中,这个类就成为简单⼯⼚类,让简单⼯⼚类来决定应该⽤哪个具体⼦类来实例化,这样做能把客户类和具体⼦类的实现解耦,客户类不再
需要知道有哪些⼦类以及应当实例化哪个⼦类
⽅法四 - 规则引擎
规则引擎适合规则很多且可能动态变化的情况,在先要搞清楚⼀点Java OOP,即类的抽象:
这⾥可以抽象出哪些类?// 头脑中需要有这种⾃动转化
规则Rule
规则接⼝
具体规则的泛化实现
表达式Expression
操作符
操作数
规则引擎
定义规则
public interface Rule {
boolean evaluate(Expression expression);
Result getResult();
}
Add 规则
public class AddRule implements Rule {
@Override
public boolean evaluate(Expression expression) {
boolean evalResult = false;
if (Operator() == Operator.ADD) {
evalResult = true;