代码整洁之道(一)之优化if-else的8种方案
我们日常开发的项目中,如果代码中存在大量的if-else语句,阅读起来非常的折磨(直接劝退),维护起来也很难,也特别容易出问题。比如说以下:
接下来,本文介绍我们常使用的8种方法去优化if-else。
1、提前return,让正常流程走主干
如果if-else代码中包含return语句,或者我们可以将包含if-else的代码从主干中抽取到一个单独方法,这样就可以在这个方法中可以return掉。这中思想也是短路求值的一种体现。把多余 else 干掉,使代码更加优雅。
- 优化前代码:
// 主流程代码
if (condition){
// doSomething
}else {
return;
}
// 主流程代码
if (condition){
// doSomething1
}else {
// doSomething2
}
- 优化后代码:
// 主流程代码
if (!condition){
return;
}
// doSomething
// 主流程代码
//doSomething
doSomething();
private static void doSomething(){
// 主流程代码
if (!condition){
// doSomething1
return;
}
// doSomething2
}
2、使用三目运算符
某些if-else可以优化为使用三目运算符,这样会让代码更简洁,可读性高。
- 优化前
int price;
if (condition1){
price = 1;
} else if (condition2) {
price = 2;
}else {
price = 0;
}
- 优化后
int price = condition1 ? 1 : (condition2 ? 2 : 0);
3、使用Optional
我们在代码中判null会导致存在大量的if-else,这个时候我们可以考虑使用Java8的Optional
去优化。
- 优化前
public static void main(String[] args) {
String s = handleStr("11");
System.out.println(s);
}
private static String handleStr(String str){
if (str != null){
return str.concat("。。。。。");
}else {
return "Null";
}
}
- 优化后代码:
public static void main(String[] args) {
String s = Optional.ofNullable(handleStr("11"))
.map(str -> str.concat("。。。。。"))
.orElse("Null");
System.out.println(s);
}
private static String handleStr(String str) {
// 其余业务逻辑,同样适用于处理一个对象,判null
return str;
}
4、多态
我们可以将一些操作(比如一些状态)的一些共性的方法抽象成一个公共接口,然后针对这些操作实现这些接口完成不同的逻辑,在调用时我们只需要传入对应的操作类即可,对外的操作方法都是同一个。
- 优化前代码
public class OrderProcessing {
public static void main(String[] args) {
processOrder("pending");
processOrder("paid");
processOrder("shipped");
}
private static void processOrder(String status) {
if ("pending".equalsIgnoreCase(status)) {
System.out.println("Handling payment for pending order.");
// 处理支付逻辑
System.out.println("Payment handled.");
System.out.println("Cannot ship. Payment pending.");
} else if ("paid".equalsIgnoreCase(status)) {
System.out.println("Payment already received.");
System.out.println("Handling shipping for paid order.");
// 处理发货逻辑
System.out.println("Order shipped.");
} else if ("shipped".equalsIgnoreCase(status)) {
System.out.println("Payment already received.");
System.out.println("Order already shipped.");
} else {
System.out.println("Invalid order status: " + status);
}
}
}
- 优化后代码
// 状态接口
interface OrderState {
void handlePayment();
void handleShipping();
}
// 具体状态类
class PendingPaymentState implements OrderState {
@Override
public void handlePayment() {
System.out.println("Payment handled for pending order.");
}
@Override
public void handleShipping() {
System.out.println("Cannot ship. Payment pending.");
}
}
class PaidState implements OrderState {
@Override
public void handlePayment() {
System.out.println("Payment already received.");
}
@Override
public void handleShipping() {
System.out.println("Shipping handled for paid order.");
}
}
class ShippedState implements OrderState {
@Override
public void handlePayment() {
System.out.println("Payment already received.");
}
@Override
public void handleShipping() {
System.out.println("Order already shipped.");
}
}
// 上下文类
class Order {
private OrderState currentState;
public Order(OrderState initialState) {
this.currentState = initialState;
}
public void handlePayment() {
currentState.handlePayment();
}
public void handleShipping() {
currentState.handleShipping();
}
public void setState(OrderState newState) {
this.currentState = newState;
}
}
public class StatePatternExample {
public static void main(String[] args) {
Order order = new Order(new PendingPaymentState());
order.handlePayment();
order.handleShipping();
order.setState(new PaidState());
order.handlePayment();
order.handleShipping();
order.setState(new ShippedState());
order.handlePayment();
order.handleShipping();
}
}
5、枚举
对一些创建了枚举值,针对不同的枚举值有不同的操作时,枚举也可以消除if-else。个人感觉有点像策略模式或者表驱动。
- 优化前
enum OperateTypeEnum{
PO(1),
PR(2),
DC_INBOUND(3),
DC_OUTBOUND(4);
public final Integer code;
OperateTypeEnum(Integer code) {
this.code = code;
}
}
private static Long getOperator(Integer operator){
if (OperateTypeEnum.PO.code.equals(operator)){
return getPoOperator();
} else if (OperateTypeEnum.PR.code.equals(operator)) {
return getPrOperator();
} else if (OperateTypeEnum.DC_INBOUND.code.equals(operator)) {
return getDcInboundOperator();
} else if (OperateTypeEnum.DC_OUTBOUND.code.equals(operator)) {
return getDcOutboundOperator();
}else {
return null;
}
}
private static Long getPoOperator(){return 1L;}
private static Long getPrOperator(){return 2L;}
private static Long getDcInboundOperator(){return 3L;}
private static Long getDcOutboundOperator(){return 4L;}
private static Long getDwInboundOperator(){return 5L;}
private static Long getDwOutboundOperator(){return 6L;}
- 优化后的代码
enum OperateTypeEnum{
PO(1){
@Override
protected Long getOperator() {
return 1L;
}
},
PR(2){
@Override
protected Long getOperator() {
return 2L;
}
},
DC_INBOUND(3){
@Override
protected Long getOperator() {
return 3L;
}
},
DC_OUTBOUND(4){
@Override
protected Long getOperator() {
return 4L;
}
};
public final Integer code;
OperateTypeEnum(Integer code) {
this.code = code;
}
public static OperateTypeEnum ofCode(Integer code){
return Arrays.stream(OperateTypeEnum.values())
.filter(e -> e.code.equals(code))
.findFirst().orElseThrow(() -> new RuntimeException("出错了"));
}
/**
* 定义一个公共方法
*/
protected abstract Long getOperator();
}
private static Long getOperator(Integer operatorType){
OperateTypeEnum operateTypeEnum = OperateTypeEnum.ofCode(operatorType);
return operateTypeEnum.getOperator();
}
这种方式也是我再处理一些枚举时,对应不同的处理逻辑时常用的一种方式。比如根据订单类型的不同返回类型对应的数据。当然我们枚举方法中处理逻辑时如果想用bean的话,可以当做参数传入或者直接从Spring容器中获取。
6、表驱动(Map+函数方法)
表驱动编程是一种通过查找表格而不是嵌套条件语句来实现的编程方法。可以使用数据结构(如数组、Map)来存储条件和对应的操作,这样就不必用很多的逻辑语句(if 或 case)来把它们找出来的方法。
- 优化前代码
private static OrderInfoVO operateOrder(String orderType, OrderInfoDO orderInfo){
if (orderType.equals("PO")){
return handlePoOrder(orderInfo);
}else if (orderType.equals("INBOUND")){
return handleInboundOrder(orderInfo);
} else if (orderType.equals("OUTBOUND")) {
return handleOutboundOrder(orderInfo);
}
}
- 优化后代码
private static OrderInfoVO handlerOrder(String orderType, OrderInfoDO orderInfo){
Map<String, Function<OrderInfoDO, OrderInfoVO>> functionMap = Maps.newHashMap();
functionMap.put("PO", (orderInfo1) -> { return handlePoOrder(orderInfo1);});
functionMap.put("INBOUND", (orderInfo1) -> { return handleInboundOrder(orderInfo1);});
functionMap.put("OUTBOUND", (orderInfo1) -> { return handleOutboundOrder(orderInfo1);});
return functionMap.get(orderType).apply(orderInfo);
}
当然Funtion
也可以根据业务需要,可以为Consumer
,Predicate
等。
不过我们也可以利用Spring的依赖注入,将其转换为对应的Map<String, Bean>。比如上述代码也可以这么优化:
interface IOrderHandler{
/**
* 定义统一的处理接口
* @param orderInfo
* @return
*/
OrderInfoVO handlerOrder(OrderInfoDO orderInfo);
}
@Component("PO")
class PoOrderHandler implements IOrderHandler{
/**
* 处理Po
*
* @param orderInfo
* @return
*/
@Override
public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {
return null;
}
}
@Component("INBOUND")
class InboundOrderHandler implements IOrderHandler{
/**
* 处理Inbound
*
* @param orderInfo
* @return
*/
@Override
public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {
// 具体处理逻辑
return null;
}
}
@Component("OUTBOUND")
class InboundOrderHandler implements IOrderHandler{
/**
* 处理Outbound
*
* @param orderInfo
* @return
*/
@Override
public OrderInfoVO handlerOrder(OrderInfoDO orderInfo) {
return null;
}
}
public class OrderSerivceImpl implements IOrderService{
@Autowired
private Map<String, IOrderHandler> orderHandlerMap;
public OrderInfoVO handleOrderInfo(String orderType, OrderInfoDO orderInfo){
IOrderHandler orderHandler = orderHandlerMap.get(orderType);
return orderHandler.handlerOrder(orderInfo);
}
}
7、策略模式+工厂模式
我们可以使用策略模式将每个条件分支抽象为一个策略类,然后在主逻辑中使用策略类来执行相应的逻辑。这种方式可以降低代码的耦合性,使得代码更加可维护和可扩展。然后再使用工厂模式定义一个策略工厂类去管理这些策略,即对外提供的都是策略工厂的方法。这种方法可以有效的去除if-else,并且代码逻辑更容易阅读维护以及扩展。
比如上例中,我们在处理不同订单类型时的handler类就是一个个的策略,我们也可以创建一个策略工厂类。
publid class OrderHandlerFactory{
private static final Map<String, IOrderHandler> orderHandlerMap = Maps.newHashMap();
static {
orderHandlerMap.put("PO", new PoOrderHandler());
orderHandlerMap.put("INBOUND", new InboundOrderHandler());
orderHandlerMap.put("OUTBOUND", new OutboundOrderHandler());
}
/**
* 获取具体处理的类
*/
public static IOrderHandler getOrderHandler(String orderType){
return orderHandlerMap.get(orderType);
}
}
8、规则引擎
使用规则引擎来管理条件和对应的执行逻辑。例如,Drools 是一个强大的规则引擎,它允许你定义规则并动态执行它们。再比如LiteFlow,EasyRule,都可以通过管理条件和对应的执行逻辑。可以消除if-else。规则引擎适合处理复杂的业务逻辑。通过编排条件去处理业务逻辑。后续会分享规则引擎相关的干货。有兴趣的同学可以关注公众号码农Academy
。
总结:
上述方案都可以达到优化if-else的效果,但是采用那种方案还是要看具体的代码逻辑以及业务处理逻辑,重要的是要评估项目的复杂性、维护性和性能需求,选择最适合项目需求的优化方案。在实际开发中,通常会根据具体情况结合多种方式来达到更好的优化效果。
本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等