一般來說,簡單的策略模式大概有這麼2種用法,分別是:
- 傳入一個參數作爲策略,然後根據參數做一些事情,比如
TreeMap
的Comparator
接口 - 傳入一個參數作爲策略,然後根據參數返回一個對應的對象,然後用戶拿到此對象做一些事情
我們在使用Spring
時往往是使用如下方式:
-
定義一個接口
Stratege
public interface Stratege { void doSomething(String param); }
-
定義2個實現類
A
和B
:@Component public static class A implements Stratege { @Override public void doSomething(String param) { // ... } }
@Component public static class B implements Stratege { @Override public void doSomething(String param) { // ... } }
-
於是就可以在某個注入類似
Map<String, Stratege>
或者List<Stratege>
對象,然後從集合中獲取相應的對象
上述方式是可以很好的運行的,以前也一直這麼用,某天看Swagger
源碼的時候發現Swagger
用了很多Plugin
方式,於是研究了一下Spring的plugin
官網上說,這是有史以來最小的插件,數了下,整個包只有十來個類,他的原理和上面方式是一樣的,也是通過傳入某個參數,然後返回一個對象的對象,只不過上面的Map
變成了PluginRegistry
對象,Map
的get(k)
方法變成了getPluginFor
或者getRequiredPluginFor
(接口還有一些其他的方法,都是類似的)
-
定義接口
參數對象
public class Param { String key; }
-
定義接口
public interface Stratege extends Plugin<Param> { void doSomething(Param param); }
-
定義2個實現類
A
和B
:@Component public class A implements Stratege { @Override public void doSomething(Param param) { // ... } @Override public boolean supports(Param delimiter) { return delimiter.key.equals("a"); } }
@Component public class B implements Stratege { @Override public void doSomething(Param param) { // ... } @Override public boolean supports(Param delimiter) { return delimiter.key.equals("b"); } }
-
在Spring啓動類頭頂增加註解:
@SpringBootApplication @EnablePluginRegistries({Stratege.class}) public class Application {}
-
於是就可以注入策略對象:
@RestController @RequestMapping("/stratege") public class StrategeController { @Resource private PluginRegistry<Stratege, Param> registry; @PostMapping("/doSomething") public void doStratege(@RequestBody Param param) { Stratege stratege = registry.getRequiredPluginFor(param); stratege.doSomething(param); } }
關於插件的運行機制,也是比較簡單,Spring的@EnableXXX
的原理都是類似的,通過註解,啓動Spring時解析註解,注入的容器
總結:Map
方式一般是通過對象名來獲取bean
,插件通過boolean supports(S delimiter)
方法作爲條件,插件方式靈活一點,但是這個插件由於比較小衆,用的人少