在 Spring Boot 中,如何干掉 if else
看到crossover Jie的文章《利用策略模式優(yōu)化過多if else 代碼》后受到啟發(fā),可以利用策略模式簡化過多的if else代碼。
需求
這里虛擬一個業(yè)務(wù)需求,讓大家容易理解。假設(shè)有一個訂單系統(tǒng),里面的一個概念是根據(jù)訂單的不同類型做出不同的處理。
項目結(jié)構(gòu)

訂單實體
/**
* 訂單實體
*/
public class OrderDTO {
private String code;
private BigDecimal price;
/*
* 訂單類型:
* 1:普通訂單
* 2:團購訂單
* 3:促銷訂單
*/
private String type;
//getter,setter自己實現(xiàn)
}
service接口
/**
* 訂單處理
*/
public interface IOrderService {
/**
* 根據(jù)訂單的不同類型做出不同的處理
*
* @param dto 訂單實體
* @return 為了簡單,返回字符串
*/
String orderHandler(OrderDTO dto);
}
//實現(xiàn)類1
@Component
public class OrderServiceImpl implements IOrderService {
@Override
public String orderHandler(OrderDTO dto) {
if ("1".equals(dto.getType())) {
//普通訂單處理
} else if ("2".equals(dto.getType())) {
//團購訂單處理
} else if ("3".equals(dto.getType())) {
//促銷訂單處理
}
//未來訂單類型增加
}
}
//實現(xiàn)類二
@Component
public class OrderServiceImpl implements IOrderService {
//使用策略模式實現(xiàn)
@Autowired
private HandlerContext handlerContext;
@Override
public String orderHandler(OrderDTO dto) {
/*
* 1:使用if..else實現(xiàn)
* 2:使用策略模式實現(xiàn)
*/
AOrderTypeHandler instance = handlerContext.getInstance(dto.getType());
return instance.handler(dto);
}
}
HandlerContext和HandlerProccessor
/**
* 訂單策略模式環(huán)境
* 這個類的注入由HandlerProccessor實現(xiàn)
*/
public class HandlerContext {
private Map<String, AOrderTypeHandler> handlerMap;
/**
* 構(gòu)造傳參不能直接使用注解掃入
*/
public HandlerContext(Map<String, AOrderTypeHandler> handlerMap) {
this.handlerMap = handlerMap;
}
/**
* 獲得實例
*
* @param type
* @return
*/
public AOrderTypeHandler getInstance(String type) {
if (type == null) {
throw new IllegalArgumentException("type參數(shù)不能為空");
}
AOrderTypeHandler clazz = handlerMap.get(type);
if (clazz == null) {
throw new IllegalArgumentException("該類型沒有在枚舉OrderTypeHandlerAnno中定義,請定義:" + type);
}
return clazz;
}
}
/**
* 策略模式,處理type與實現(xiàn)類的映射關(guān)系
*/
@Component
public class HandlerProccessor implements BeanFactoryPostProcessor {
/**
* 掃描@OrderTypeHandlerAnno注解,初始化HandlerContext,將其注冊到spring容器
*
* @param beanFactory bean工廠
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, AOrderTypeHandler> handlerMap = new HashMap<>();
for (OrderTypeEnum temp : OrderTypeEnum.values()) {
AOrderTypeHandler beanInstacle = getBeansWithAnnotation(beanFactory, AOrderTypeHandler.class, OrderTypeHandlerAnno.class, temp.getCode());
handlerMap.put(temp.getCode(), beanInstacle);
}
HandlerContext context = new HandlerContext(handlerMap);
//單例注入
beanFactory.registerSingleton(HandlerContext.class.getName(), context);
}
/*
* 通過父類+注解找到實體類
*/
private <T> T getBeansWithAnnotation(ConfigurableListableBeanFactory beanFactory, Class<T> manager, Class<? extends OrderTypeHandlerAnno> annotation, String code) throws BeansException {
if (ObjectUtils.isEmpty(code)) {
throw new RuntimeException("code is null ");
}
Collection<T> tCollection = beanFactory.getBeansOfType(manager).values();
for (T t : tCollection) {
OrderTypeHandlerAnno orderTypeHandlerAnno = t.getClass().getAnnotation(annotation);
if (ObjectUtils.isEmpty(orderTypeHandlerAnno)) {
throw new RuntimeException("該注解沒有寫入值 :" + code);
}
//注解值是否與code相等
if (code.equals(orderTypeHandlerAnno.value().getCode())) {
return t;
}
}
throw new RuntimeException("通過code沒有找到該注解對應(yīng)的實體類 :" + code);
}
}
父抽象類+注解+枚舉
/**
* 訂單類型處理定義
* 使用抽象類,那么子類就只有一個繼承了
*/
public abstract class AOrderTypeHandler {
/**
* 一個訂單類型做一件事
*
* @param dto 訂單實體
* @return 為了簡單,返回字符串
*/
abstract public String handler(OrderDTO dto);
}
/**
* 訂單類型注解
* 使用方式:
* 1:普通訂單 @OrderTypeHandlerAnno("1")
* 2:團購訂單 @OrderTypeHandlerAnno("2")
* 3:促銷訂單 @OrderTypeHandlerAnno("3")
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderTypeHandlerAnno {
OrderTypeEnum value();
}
/**
* 訂單類型枚舉
*/
public enum OrderTypeEnum {
Normal("1", "普通"),
Group("2", "團隊"),
Promotion("3", "促銷");
private String code; //代碼
private String name; //名稱,描述
OrderTypeEnum(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 根據(jù)code屬性獲取name屬性
*
* @param code
* @return
*/
public static String getNameByCode(String code) {
for (OrderTypeEnum temp : OrderTypeEnum.values()) {
if (temp.getCode().equals(code)) {
return temp.getName();
}
}
return null;
}
}
//業(yè)務(wù)代碼
/**
* 普通訂單處理
*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Normal)
public class NormalOrderHandler extends AOrderTypeHandler {
@Override
public String handler(OrderDTO dto) {
return "處理普通訂單";
}
}
/**
* 團隊訂單處理
*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Group)
public class GroupOrderHandler extends AOrderTypeHandler {
@Override
public String handler(OrderDTO dto) {
return "處理團隊訂單";
}
}
/**
* 促銷訂單處理
*/
@Component
@OrderTypeHandlerAnno(OrderTypeEnum.Promotion)
public class PromotionOrderHandler extends AOrderTypeHandler {
@Override
public String handler(OrderDTO dto) {
return "處理促銷訂單";
}
}
測試結(jié)果(使用chrome瀏覽器測試結(jié)果)




controller
/**
* 策略模式
*/
@RestController
public class StrategyController {
@Resource(name = "orderServiceImpl")
private IOrderService orderService;
@GetMapping("/api/order")
@ResponseBody
public String orderSave(OrderDTO dto) {
String str = orderService.orderHandler(dto);
return "{\"status\":1,\"msg\":\"保存成功\",\"data\":\"" + str + "\"}";
}
}
pom.xml文檔
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kayak</groupId>
<artifactId>study-design</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>study-design</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>總結(jié):
利用策略模式可以簡化復(fù)雜的if else代碼,方便維護,而利用自定義注解和自注冊的方式,可以方便應(yīng)對需求的變更。
評論
圖片
表情
