一、介紹
一說起策略設(shè)計(jì)模式,相比大家都不陌生,在實(shí)際的業(yè)務(wù)開發(fā)中,合理地使用設(shè)計(jì)模式來編程,可以讓代碼閱讀起來層次感更強(qiáng),同時(shí)擴(kuò)展性也會(huì)得到提升!
最近看同事的代碼的時(shí)候,學(xué)到了一個(gè)小技巧,在某些場景下合理地使用策略模式還是非常有用的,在此分享一下給大家。
二、代碼實(shí)踐
在介紹 SpringBoot 在如何實(shí)現(xiàn)策略設(shè)計(jì)模式之前,我們先簡單地回顧一下策略模式的設(shè)計(jì)思路。
以編寫一個(gè)簡單的程序計(jì)算器,代碼如下!
public interface Operation { /** * 執(zhí)行計(jì)算 * @param a * @param b * @return */ int execute(int a, int b);}
- 接著,分別將四個(gè)if判斷邏輯獨(dú)立成一個(gè)模塊,來單獨(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)建一個(gè)工廠類,用于處理客戶端傳入的參數(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 } /** * 獲取對(duì)應(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) { //獲取計(jì)算的目標(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); }}
以上就是一個(gè)典型的策略模式的實(shí)踐思路,從代碼閱讀性、擴(kuò)展性角度看,還是非常干凈利落的。
那么,在SpringBoot項(xiàng)目中,我們應(yīng)該如何使用呢?
三、SpringBoot 實(shí)踐應(yīng)用
3.1、方案一
- 首先,我們還是定義一個(gè)Command接口,用于方法的抽象和統(tǒng)一
public interface Command { /** * 命令類型 * @return */ String operateType(); /** * 執(zhí)行 * @param a * @param b * @return */ Integer execute(int a, int b);}
- 接著,編寫四套不同的計(jì)算處理邏輯
@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; }}
- 然后,編寫一個(gè)類似于上文的策略處理類
@Componentpublic class CalculatorService implements ApplicationContextAware { private Map commandMap = new ConcurrentHashMap(); /** * 執(zhí)行計(jì)算 * @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 啟動(dòng)時(shí),會(huì)將對(duì)象注入到IOC容器。
3.2、方案二(推薦)
翻查Spring的ioc容器,你會(huì)發(fā)現(xiàn)一個(gè)秘密,當(dāng)一個(gè)接口有多個(gè)實(shí)現(xiàn)類時(shí),Spring會(huì)自動(dòng)將Strategy接口的實(shí)現(xiàn)類注入到這個(gè)Map中,key為bean id,value值則為對(duì)應(yīng)的策略實(shí)現(xiàn)類。
簡單的說,我們只需要通過@Autowired注入對(duì)象,不需要通過CalculatorService這個(gè)類進(jìn)行單獨(dú)配置,操作方式如下!
- 首先,編寫一個(gè)CommandFactory工廠類,用于邏輯的處理
@Componentpublic class CommandFactory { /** * Spring會(huì)自動(dòng)將Strategy接口的實(shí)現(xiàn)類注入到這個(gè)Map中,key為bean id,value值則為對(duì)應(yīng)的策略實(shí)現(xiàn)類 */ @Autowired private Map commandMap; /** * 執(zhí)行計(jì)算 * @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策略處理類來初始化對(duì)象,Spring在初始化對(duì)象的時(shí)候,可以幫忙我們實(shí)現(xiàn)對(duì)象的注入!
四、小結(jié)
本文主要圍繞在 SpringBoot 引入策略模式的設(shè)計(jì)思路和實(shí)踐方法進(jìn)行介紹,在實(shí)際的業(yè)務(wù)開發(fā)中,合理地使用策略模式,能讓代碼看起來更加清爽,業(yè)務(wù)擴(kuò)展性也更佳強(qiáng)大,希望能幫助到大家!