一、介紹
一說起策略設(shè)計模式,相比大家都不陌生,在實(shí)際的業(yè)務(wù)開發(fā)中,合理地使用設(shè)計模式來編程,可以讓代碼閱讀起來層次感更強(qiáng),同時擴(kuò)展性也會得到提升!
最近看同事的代碼的時候,學(xué)到了一個小技巧,在某些場景下合理地使用策略模式還是非常有用的,在此分享一下給大家。
二、代碼實(shí)踐
在介紹 SpringBoot 在如何實(shí)現(xiàn)策略設(shè)計模式之前,我們先簡單地回顧一下策略模式的設(shè)計思路。
以編寫一個簡單的程序計算器,代碼如下!
public interface Operation { /** * 執(zhí)行計算 * @param a * @param b * @return */ int execute(int a, int b);}
- 接著,分別將四個if判斷邏輯獨(dú)立成一個模塊,來單獨(dú)處理
public class AddOperation implements Operation { @Override public int execute(int a, int b) { return a + b; }}public class SubOperation implements Operation { @Override public int execute(int a, int b) { return a – b; }}public class MultiOperation implements Operation { @Override public int execute(int a, int b) { return a * b; }}public class DivOperation implements Operation { @Override public int execute(int a, int b) { return a / b; }}
- 然后,創(chuàng)建一個工廠類,用于處理客戶端傳入的參數(shù)
public class OperatorFactory { private static Map operationMap = new HashMap(); static { //初始化實(shí)現(xiàn)類 operationMap.put(“add”, new AddOperation()); operationMap.put(“sub”, new SubOperation()); operationMap.put(“multi”, new MultiOperation()); operationMap.put(“p”, new DivOperation()); // more operators } /** * 獲取對應(yīng)的目標(biāo)實(shí)現(xiàn)類 * @param operator * @return */ public static Optional getOperation(String operator){ return Optional.ofNullable(operationMap.get(operator)); }}
- 最后,在需要的地方引入方法即可!
public class OperatorTestMain { public static void main(String[] args) { //獲取計算的目標(biāo)實(shí)現(xiàn)類 Operation targetOperation = OperatorFactory .getOperation(“add”) .orElseThrow(() -> new IllegalArgumentException(“Invalid Operator”)); int result = targetOperation.execute(1, 2); System.out.println(“result:” + result); }}
以上就是一個典型的策略模式的實(shí)踐思路,從代碼閱讀性、擴(kuò)展性角度看,還是非常干凈利落的。
那么,在SpringBoot項(xiàng)目中,我們應(yīng)該如何使用呢?
三、SpringBoot 實(shí)踐應(yīng)用
3.1、方案一
- 首先,我們還是定義一個Command接口,用于方法的抽象和統(tǒng)一
public interface Command { /** * 命令類型 * @return */ String operateType(); /** * 執(zhí)行 * @param a * @param b * @return */ Integer execute(int a, int b);}
- 接著,編寫四套不同的計算處理邏輯
@Componentpublic class AddCommand implements Command { @Override public String operateType() { return “add”; } @Override public Integer execute(int a, int b) { return a + b; }}@Componentpublic class SubCommand implements Command { @Override public String operateType() { return “subtract”; } @Override public Integer execute(int a, int b) { return a – b; }}@Componentpublic class MultiCommand implements Command { @Override public String operateType() { return “multiply”; } @Override public Integer execute(int a, int b) { return a * b; }}@Componentpublic class DivCommand implements Command { @Override public String operateType() { return “pide”; } @Override public Integer execute(int a, int b) { return a / b; }}
- 然后,編寫一個類似于上文的策略處理類
@Componentpublic class CalculatorService implements ApplicationContextAware { private Map commandMap = new ConcurrentHashMap(); /** * 執(zhí)行計算 * @param operateType * @param a * @param b * @return */ public int calculate(String operateType,int a, int b){ Command targetCommand = Optional.ofNullable(commandMap.get(operateType)) .orElseThrow(() -> new IllegalArgumentException(“Invalid Operator”)); return targetCommand.execute(a,b); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map tempMap = applicationContext.getBeansOfType(Command.class); tempMap.values().forEach(source -> commandMap.put(source.operateType(), source)); }}
- 最后,我們只需要在適當(dāng)?shù)奈恢脩?yīng)用即可!
@RunWith(SpringRunner.class)@SpringBootTestpublic class CalculatorServiceTest { @Autowired private CalculatorService calculatorService; @Test public void test(){ int result = calculatorService.calculate(“add”, 1,2); System.out.println(“result:” + result); }}
總結(jié):這種方案的實(shí)踐,和上面介紹的思路基本上一致,不同的地方在于,當(dāng) springboot 啟動時,會將對象注入到IOC容器。
3.2、方案二(推薦)
翻查Spring的ioc容器,你會發(fā)現(xiàn)一個秘密,當(dāng)一個接口有多個實(shí)現(xiàn)類時,Spring會自動將Strategy接口的實(shí)現(xiàn)類注入到這個Map中,key為bean id,value值則為對應(yīng)的策略實(shí)現(xiàn)類。
簡單的說,我們只需要通過@Autowired注入對象,不需要通過CalculatorService這個類進(jìn)行單獨(dú)配置,操作方式如下!
- 首先,編寫一個CommandFactory工廠類,用于邏輯的處理
@Componentpublic class CommandFactory { /** * Spring會自動將Strategy接口的實(shí)現(xiàn)類注入到這個Map中,key為bean id,value值則為對應(yīng)的策略實(shí)現(xiàn)類 */ @Autowired private Map commandMap; /** * 執(zhí)行計算 * @param operateType * @param a * @param b * @return */ public int calculate(String operateType,int a, int b){ Command targetCommand = Optional.ofNullable(commandMap.get(operateType)) .orElseThrow(() -> new IllegalArgumentException(“Invalid Operator”)); return targetCommand.execute(a,b); }}
- 最后,直接在合適的地方使用CommandFactory即可!
@RunWith(SpringRunner.class)@SpringBootTestpublic class CalculatorServiceTest { @Autowired private CommandFactory commandFactory; @Test public void test(){ int result = commandFactory.calculate(“addCommand”, 1,2); System.out.println(“result:” + result); }}
總結(jié):方案二和方案一的不同點(diǎn)在于,不需要顯式的編寫CalculatorService策略處理類來初始化對象,Spring在初始化對象的時候,可以幫忙我們實(shí)現(xiàn)對象的注入!
四、小結(jié)
本文主要圍繞在 SpringBoot 引入策略模式的設(shè)計思路和實(shí)踐方法進(jìn)行介紹,在實(shí)際的業(yè)務(wù)開發(fā)中,合理地使用策略模式,能讓代碼看起來更加清爽,業(yè)務(wù)擴(kuò)展性也更佳強(qiáng)大,希望能幫助到大家!