本文介紹了如何在Springboot項目中通過ApplicationContext獲取接口的實現類,并通過枚舉策略模式避免if/else,展示了如何使用`getBeansOfType`獲取`TrafficModeService`的實現,以及如何在實際場景中應用,如查詢交通方式費用
1 在實際工作中,我們經常會遇到一個接口及多個實現類的情況,并且在不同的條件下會使用不同的實現類。
應用場景
springboot?項目中通過 ApplicationContext.getBeansOfType(class) 獲取某一接口的所有實現類,并通過枚舉完成策略模式,替代 if/else,使代碼更加優雅易于拓展。
三、ApplicationContext.getBeansOfType(class) 介紹
? ? <T> Map<String, T> getBeansOfType(@Nullable Class<T> var1) throws BeansException;
從上面的源碼上我們可以看出來這個方法能返回一個接口的全部實現類(前提是所有實現類都必須由 Spring IoC 容器管理)?
Map<String, TrafficModeService> map = applicationContext.getBeansOfType(TrafficModeService.class);
從上面的代碼上(下面案例中工廠類有) ,Map 中的 String 的值是各個實現類的名稱 busModeServiceImpl、trainModeServiceImpl(首字母小寫),Map 中的 value 是各個 key 對應的策略實現類
案例 demo
1、TrafficCodeEmun 枚舉制定接口信息@AllArgsConstructor
public enum TrafficCodeEmun {TRAIN("TRAIN","火車"),BUS("BUS","大巴"),;private final String code;private final String desc;
}2、TrafficModeFactory 工廠類獲取接口實現 bean,并存儲到 ConcurrentHashMap,通過枚舉獲取對應的實現 bean@Component
@Slf4j
public class TrafficModeFactory implements ApplicationContextAware {public static final ConcurrentHashMap<TrafficCodeEmun, TrafficModeService> TRAFFIC_BEAN_MAP = new ConcurrentHashMap<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {log.info("TrafficModeFactory 啟動開始");Map<String, TrafficModeService> map = applicationContext.getBeansOfType(TrafficModeService.class);map.forEach((key, value) -> TRAFFIC_BEAN_MAP.put(value.getCode(), value));log.info("TrafficModeFactory 啟動完成");}public static <T extends TrafficModeService> T getTrafficMode(TrafficCodeEmun code) {return (T) TRAFFIC_BEAN_MAP.get(code);}}3、定義策略接口 TrafficModeServicepublic interface TrafficModeService {/*** 查詢交通方式編碼* @return 編碼*/TrafficCodeEmun getCode();/*** 查詢交通方式的費用,單位:分* @return 費用*/Integer getFee();}4、策略實現類 BusModeServiceImpl、TrainModeServiceImpl@Service
public class TrainModeServiceImpl implements TrafficModeService {/*** 查詢交通方式編碼* @return 編碼*/@Overridepublic TrafficCodeEmun getCode() {return TrafficCodeEmun.TRAIN;}/*** 查詢交通方式的費用,單位:分* @return 費用*/@Overridepublic Integer getFee() {return 5000;}}5、定義 controller@PostMapping("/test3")public Integer test3() {Integer fee = TrafficModeFactory.getTrafficMode(TrafficCodeEmun.TRAIN).getFee();return fee;}注意點:
一個策略接口被多個策略實現類所實現,具體使用哪一種根據用戶選擇的類型來和 Map 里的 key 做匹配,獲取對應的實現來調用具體的策略方法。
使用 ConcurrentHashMap ,而不使用 HashMap ,是 put 的時候,鍵和值都不能為空,防止 key 對應的實現類沒有注入進去,導致空指針的問題。