如何在Spring中使用責任鏈設計模式
如何在Spring中使用責任鏈設計模式
筆者文筆功力尚淺,如有不妥,請慷慨指出,必定感激不盡
本片文章不是講Spring原始碼中使用責任鏈的設計例項,而是會講在Spring中如何設計自己的責任鏈並且如何呼叫。
責任鏈設計模式作為我們常用的設計模式之一,用途非常的廣,例如在一些流程化的執行中、或者是一些動態攔截中我們都可以使用責任鏈設計模式進行設計需求,從而使我們的專案無論是可用性還是可擴充套件性都會非常的好。
大家對於責任鏈還有不瞭解的可以看我之前的博文設計模式——責任鏈模式
如何定義鏈條
在Java開發中我們如果想要自己定義一個鏈條,其實非常簡單,也就定義一個抽象類,然後定義幾個實現方法,然後設定其next屬性即可,但是在Spring中如何將框架與我們的鏈條結合起來呢?其實這裡用到了三個註解@Component
@Order
、@PostConstruct
。
-
@Component
:將我們的子類交給Spring管理 -
@Order
:定義我們鏈條的順序 -
@PostConstruct
:程式啟動時將我們鏈條組合起來
接下來我們直接看程式碼,首先來看抽象類,其實責任鏈的抽象類基本上都一樣的。
1public abstract class PrintChainPattern {
2
3 private PrintChainPattern next;
4
5 public final void print() {
6 String message = getMessage();
7
8 log.info("{} : {}",message,message);
9 if (getNext()!=null){
10 getNext().print();
11 }
12 }
13 abstract String getMessage();
14}
複製程式碼
然後我們看實現類,後面有四個實現類,依次返回是two
、three
、four
。@Order
註解中數字依次遞增。這裡只演示第一個實現類的程式碼。
1@Order(1)
2@Component
3public OnePrintChainPattern extends PrintChainPattern {
4 @Override
5 public String 6 return "one";
7 }
8}
複製程式碼
接下來就到了如何利用Spring來組裝我們的鏈條了
1@Configuration
2InitPrintChainPattern {
3
4 @Autowired
5 private List<PrintChainPattern> printChainPatterns;
6
7 @PostConstruct
8 private initPrintChainPattern(){
9 Collections.sort(printChainPatterns, AnnotationAwareOrderComparator.INSTANCE);
10
11 int size = printChainPatterns.size();
12 for (int i = 0; i < size; i++) {
13 if (i == size-1){
14 printChainPatterns.get(i).setNext(null);
15 }else {
16 printChainPatterns.get(i).setNext(printChainPatterns.get(i+1));
17 }
18 }
19 }
20
21 print(int index){
22 printChainPatterns.get(index-1).print();
23 }
24}
複製程式碼
這裡我們可以看到在@PostConstruct
方法中我們做了兩件事
- 將
List
中按照@Order
註解的數字進行排序 - 依次設定每個節點的next值
這樣我們就已經將這個鏈條組合了起來。接下來我們就可以隨意的對這個鏈條進行操作,例如我下面的print()
方法中,就是根據傳進來的值的不同會從不同的節點進行執行。
如何在抽象類中使用@Autowired
在上面我們已經將我們鏈條組合了起來,但是如果我們的所有子類都公有一些類的話,那麼這個類就要放在抽象類中。那麼如果這個類我們想要從Spring的容器中取得呢?
比如我們有如下的類交給了Spring管理,我們所有子類都要使用這個類。
1@Bean
2public User setUser(){
3 return User.builder().name("張三").age(14).build();
4}
複製程式碼
只需要在抽象類中定義一次即可,只需要在set
方法上加@Autowired
註解就能夠將Spring容器中的類給注入進來。
1private User user;
2
3@Autowired
4setUser(User user){
5 this.user = user;
6}
複製程式碼
然後在子類中直接呼叫getUser()
方法就行
Override
2public String getMessage() {
log.info("name:{},age:{}",52); word-wrap: inherit !important; word-break: inherit !important;" class="hljs-selector-tag">getUser().getName(),38); word-wrap: inherit !important; word-break: inherit !important;" class="hljs-selector-class">.getAge());
4 return "one";
5}
複製程式碼
如何在列舉類中使用@Autowired
為什麼要在列舉類中使用@Autowired
,是因為我在做需求時將責任鏈設計模式和策略模式結合起來做了,關於策略模式不明白的話可以看我之前的文章設計模式——策略模式。我們可以使用列舉類使我們的程式碼更加清晰可見。
我們定義一個簡單的列舉策略模式的列舉類。例如我們在這裡面要使用Spring容器中得了類的話,我們該如何寫呢?例如還是User
類。
enum HumanEnum {
3 MAN("man"){
4 @Override
5 invoke() {
6 log.info("i am man");
7 }
8 },
9 WOMAN("woman"){
10 @11 12 log.info("i am woman");
13 }
14 };
15
16 String value;
17
18 HumanEnum(String value){
19 this.value = 20 }
21
22 abstract );
23}
複製程式碼
只需要在列舉類中定義一個內部類,然後將注入進來的類賦值給列舉類即可。
1User user;
3setUse 4 5}
7 8static HumanEnumInjector{
9
10 11 private User user;
12
13 @PostConstruct
14 setValue(){
15 for (HumanEnum humanEnum : EnumSet.allOf(HumanEnum.class)){
16 humanEnum.setUse(user);
17 }
18 }
19}
複製程式碼
本文程式碼地址
總結
面向物件的三大特性:封裝、繼承、多型
- 大部分的設計模式都是圍繞著面向物件的三大特性進行演化的
-
@Autowired
也可以定義在方法上,之前只是習慣將其定義在欄位上 - 注重基礎,複雜的設計肯定也是通過一個一個簡單的設計將其拼合的