引言
在日常开发中我们常常遇到有多个if else的情况,之间书写显得代码冗余难看,对于追求更高质量代码的同学,就会思考如何优雅地处理这种代码
下面我们来探讨下几种优化if else的方法
1. switch
switch方法针对枚举值处理有不错的效果,比如针对不同的订单状态时要做不同的处理,因为状态值有限,这时我们就可以直接使用switch来针对不同状态做不同的处理:
原语句
<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void before(Integer status) {
if(status == 1){
System.out.println("订单未接单");
}else if(status == 2){
System.out.println("订单未发货");
}else if(status == 3){
System.out.println("订单未签收");
}else{
System.out.println("订单已签收");
}
}
switch
<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void greater(Integer status) {
switch (status){
case 1:
System.out.println("订单未接单");
break;
case 2:
System.out.println("订单未发货");
break;
case 3:
System.out.println("订单未签收");
break;
default:
System.out.println("订单已签收");
}
}
总结:
switch语句适用于判断条件有限且不需要经过复杂的计算,处理语句简单的场景。如果我们的判断条件需要经过一系列复杂的计算才能得到,或者处理语句逻辑也比较复杂时,我们就要考虑其他的处理方式了,毕竟在case中书写一大堆处理语句并不算得让人舒适的事情
2. 函数式接口
针对比较复杂的处理逻辑时,我们偏向于将这些处理逻辑单独抽离出来,而不是还放在一个方法里处理,增加整体的可读性和解耦性,也是我们衍生出利用函数式接口来处理if else的模式
函数式接口map处理if else的要义,是将各个条件的复杂处理逻辑单独抽取为一个函数式接口方法,通过统一的判断条件来调用不同的方法,具体示例如下
<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Component
public class FunctionInterfaceStrategy {
/**
* key 方法参数,多个参数可以自定义一个实体类处理
* value 方法返回值
*/
private Map<Integer, Function<Object,Boolean>> operationMap;
@PostConstruct
private void init(){
operationMap = new HashMap<>();
operationMap.put(1,this::takeOrder);
operationMap.put(2,this::sendOrder);
operationMap.put(3,this::signOrder);
operationMap.put(4,this::finishOrder);
}
public Boolean doOperation(Object params,Integer status){
return operationMap.get(status) == null || operationMap.get(status).apply(params);
}
private Boolean takeOrder(Object params){
// TODO 比较复杂的处理逻辑
System.out.println("订单未接单");
return true;
}
private Boolean sendOrder(Object params){
// TODO 比较复杂的处理逻辑
System.out.println("订单未发货");
return true;
}
private Boolean signOrder(Object params){
// TODO 比较复杂的处理逻辑
System.out.println("订单未签收");
return true;
}
private Boolean finishOrder(Object params){
// TODO 比较复杂的处理逻辑
System.out.println("订单已签收");
return true;
}
}
调用时就不用再用if else区分了,直接传入参数到function map中调用
<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Autowired
private FunctionInterfaceStrategy functionInterfaceStrategy;
functionInterfaceStrategy.doOperation("参数",1);
当然我们上述演示的是有参数有返回值的函数式接口,实际生产中我们可能还需要其他形式的函数式接口,我们将其单独罗列出来,供大家参考使用
3. 策略模式
上述的函数式接口的形式,实际上是针对方法进行了分离,所有的实现方法还是放在了一个类里,即使你可以在 FunctionInterfaceStrategy
类中通过依赖注入的形式再次调用其他类的方法,但是这样的模式,已经趋近于我们要将的下一种方法,即使用策略模式来解决 if else
策略模式的形式适用于实现方法更加复杂的情况,需要将处理逻辑解耦的更加干净的场景
1、首先我们需要创建一个接口类,用来规定我们后续的实现类的格式
<pre class="prettyprint hljs php" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public interface OrderStrategy {
/**
* 获取实现类标识
* @return
*/
Integer getType();
/**
* 逻辑处理
* @param params
* @return
*/
Boolean handler(Object params);
}
2、其次针对每个判断条件创建一个实现类
<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Service
public class SendOrderStrategy implements OrderStrategy{
@Override
public Integer getType() {
return 2;
}
@Override
public Boolean handler(Object params) {
// TODO 复杂的处理逻辑
System.out.println("订单未发货");
return true;
}
}
@Service
public class SignOrderStrategy implements OrderStrategy{
@Override
public Integer getType() {
return 3;
}
@Override
public Boolean handler(Object params) {
// TODO 复杂的处理逻辑
System.out.println("订单未签收");
return true;
}
}
@Service
public class TakeOrderStrategy implements OrderStrategy{
@Override
public Integer getType() {
return 1;
}
@Override
public Boolean handler(Object params) {
// TODO 复杂的处理逻辑
System.out.println("订单未接单");
return true;
}
}
3、创建一个策略工厂类,承装实现类
<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Component
@AllArgsConstructor
public class OrderStrategyFactory {
private final List<OrderStrategy> orderStrategyList;
private static Map<Integer,OrderStrategy> strategyMap = new HashMap<>();
@PostConstruct
private void init(){
for (OrderStrategy orderStrategy : orderStrategyList) {
strategyMap.put(orderStrategy.getType(),orderStrategy);
}
}
/**
* 执行方法
* @param status
* @param params
* @return
*/
public Boolean handler(Integer status,Object params){
return strategyMap.get(status).handler(params);
}
}
4、方法调用
<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@RestController
@RequestMapping("ifelse")
@AllArgsConstructor
public class IfElseController {
private final OrderStrategyFactory orderStrategyFactory;
@GetMapping("strategy")
public Boolean strategy(Integer status){
return orderStrategyFactory.handler(status,"1");
}
}
总结:
通过上述的代码示例,大家其实可以发现,函数式接口和策略模式有异曲同工之处,根本区别在于是否需要将实现方法单独抽取为一个实现类。抽取的粒度越细也就说明解耦越强
使用策略模式,后续如果需要增加if else条件的话,只需要增加实现类即可,针对后续的处理更加方便
最终使用哪一个还需要根据具体的业务情况而定
4. 卫语句
我们经常需要在方法前处理各种参数嵌套判断逻辑,如果不满足条件就直接返回了,这种情况更加推荐使用卫语句来处理
原语句
<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void before(Integer status) {
if(status != null) {
if(status != 0){
if(status == 1){
System.out.println("订单未接单");
}
}
}
}<
卫语句
<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void greater(Integer status) {
if(status == null){
return;
}
if(status != 0){
return;
}
if(status == 1){
System.out.println("订单未接单");
}
}