責任鏈和策略設計模式-基於Java程式語言

語言: CN / TW / HK

作者:京東物流 鍾磊

1 前言

最近在梳理介面邏輯的時候發現,程式碼中使用的策略和責任鏈設計模式給我留下了非常深刻的印象。一個業務邏輯流程通常非常適合使用責任鏈和策略設計模式來實現,因為一個業務需求通常可以拆分成一個個獨立的邏輯處理單元並按順序組合而成,而責任鏈設計模式可以很好的連結整個業務流程,同時策略設計模式可以將業務中變化的演算法部分抽離出來,從而複用主要的公共邏輯並可以靈活替換業務演算法,使用這兩種設計模式可以靈活擴充套件我們的程式碼以適應不同的業務需求。由於這兩種設計模式非常實用,下面簡單介紹一下我對這兩種設計模式的理解和它們在Spring框架原始碼中的應用。

2 責任鏈設計模式的一般定義

責任鏈設計模式是設計模式中的一種行為型設計模式。其基礎結構類似於一個鏈條,整個鏈條由一個個單獨的鏈環組成,每個鏈環在程式程式碼中就是一個獨立的處理單元,每個處理單元都有自己負責的獨特邏輯,當一個處理請求來到這個鏈條後,會依次沿著每個處理單元進行傳遞直到這個請求被處理完畢為止。

2.1 使用場景:

1.一個業務請求需要經過一組處理單元的處理。這種場景類似於一個業務邏輯流程中設定了多個功能不同的處理單元,一個業務請求需要經過這多個處理單元的序列處理。

 



2.程式中存在能處理同一個請求的多個處理單元,但決定具體使用哪個處理單元需要在程式執行時根據請求動態確定。

 



2.2 類圖結構和Spring AOP框架中的應用

1:類圖結構

 

 



2:責任鏈設計模式在Spring AOP框架中的應用

Spring框架中的AOP模組就使用了責任鏈設計模式將目標方法的一次呼叫過程包裝成了一條方法呼叫鏈來增強目標方法。Spring AOP模組中包括了Before、After、AfterReturning、AfterThrowing、Around這五種通知方法,Spring AOP模組將這些通知方法和目標方法通過動態代理的方式包裝成了一條呼叫鏈來分別履行各個通知模組的處理邏輯,下面是Spring AOP的原始碼分析圖。

 



Spring AOP通過遞迴的方式來實現責任鏈的功能,首先將所有的通知方法進行排序,然後利用一個List索引來控制整個執行流程的開始和結束,在整個責任鏈中Before通知負責執行前置處理,After通知負責執行後置處理,AfterReturning方法負責在目標方法成功執行返回後執行處理邏輯,AfterThrowing方法負責在目標方法異常執行後執行處理邏輯。Spring AOP將通知方法包裝成方法呼叫鏈上的每一個節點,巧妙地利用責任鏈模式完成了目標方法的處理增強。

3:泛化的責任鏈設計模式

在日常程式碼的編寫中,責任鏈設計模式並不需要如此嚴格的結構,只要程式碼整體流程由一個個獨立的處理單元構成,並且按一定順序組合組合而成,那麼也可以看作是一種更加泛化的責任鏈設計模式,也能很好的滿足開閉原則,例如下面這種更加常用的程式碼結構。

 



上面這種結構同樣也能實現責任鏈處理功能,也可以更加簡潔的進行編寫,同樣可以很好的進修改和靈活擴充套件,在維護程式碼的適合也會更加清晰。

2.3 責任鏈模式的優點:

1.每個處理節點都有自己的獨特的處理邏輯,明確各自在整個流程中的職責,符合類的單一職責原則。

2.構建的責任鏈可以根據業務需求進行靈活改變,能動態進行順序調整以及動態插拔,滿足重要的開閉原則。

3.降低了請求傳送者以及請求處理者之間的耦合度。

3 策略設計模式的一般定義

策略設計模式同樣也是設計模式中的一種行為型設計模式,其在結構上的表現就是將可變的演算法策略部分從業務程式碼邏輯中獨立出來,將這些演算法策略形成策略池,從而可以隨時替換和更新,使得我們的程式碼結構更加靈活、更易擴充套件。

3.1 使用場景

1:當代碼需要根據上下文邏輯來選擇使用不同的業務演算法時,我們可以使用策略設計模式來優化程式碼的判斷結構,從而避免大量的if/else分支判斷。

 



2:當代碼的主體處理邏輯大致相同,僅僅在部分的業務演算法上存在不同時,可以將這些不同的業務演算法抽離出來,從而能避免大量重複的程式碼編寫,並能複用主體程式碼邏輯。

 



3.2 類圖結構和Spring框架中的應用

1:類圖結構

 

 



2:Spring框架中的應用

Spring框架中給我們開發者留下了非常多的擴充套件策略點,實現了可動態插拔的功能擴充套件,其中典型的一個策略擴充套件點就是BeanPostProcessor介面,BeanPostProcessor介面允許我們在Bean的初始化前和初始化後做一些邏輯處理策略來改變Bean的屬性,允許我們對Bean進行改造和個性化,Spring AOP就是利用BeanPostProcessor這個策略擴充套件點實現了動態代理Bean的建立,下面是Spring AOP後置處理器的原始碼分析。

 



Spring AOP通過匯入AspectJAwareAdvisorAutoProxyCreator這個實現了BeanPostProcessor介面的後置處理器,在Bean初始化後進行了一個動態代理類的建立,其在postProcessAfterInitaliztion方法中的WarpIfNecessary中方法中實現了代理類的建立。Spring框架利用這種模板加策略的設計模式讓我們可以個性化擴充套件框架的功能,讓框架變得非常靈活可擴充套件,我們也可以根據業務需求加入自己的BeanPostProcessor策略來實現自己的獨特邏輯,很好地滿足了重要的開閉設計原則。

3:泛化的策略設計模式

同樣地我們也不必嚴格按照定義的策略設計模式進行編寫,只要在整體上滿足業務主體邏輯不變,將變化部分抽離出來,形成可以按需擴充套件的策略思想就行了,下面以SpringBoot自動裝配的原始碼來說明這種更加泛化的策略模式。SpringBoot自動裝配機制是按照使用者當前的程式碼執行環境並結合@Conditional註解來動態為我們自動載入需要使用的類,這種策略設計模式是一種更加泛化的策略設計模式,同樣滿足策略設計模式的按需選擇,動態插拔的設計原則。SpringBoot的自動裝配機制的原理如下:

SpringBoot在@EnableAutoConfiguration註解中使用了@import註解匯入了
EnableAutoConfigurationImportSelector類。

 



利用EnableAutoConfigurationImportSelector類的selectImports方法來載入jar包裡面META-INF/spring.factories檔案中配好的類。

 



 



最後結合各種@Conditional註解來實現按需載入的策略設計模式。

 



SpringBoot這種按需自動裝配的策略設計思想,在結構上並不嚴格符合策略設計模式的結構,但他的整體設計思想非常符合策略設計模式,我們在專案中也可以通過配置檔案的方式來靈活切換我們程式碼中使用的策略演算法。

3.3 策略設計模式的優點:

1:可以在程式執行時動態選擇切換需要使用的獨立業務演算法。

2:將可變的業務演算法與業務主體邏輯剝離,實現更加靈活的維護和擴充套件。

3:滿足開閉原則,無需修改原有的程式碼邏輯就能實現不同業務演算法靈活切換。

4 結合策略設計模式和責任鏈設計模式

將策略設計模式和責任鏈設計模式進行結合就能形成靈活可擴充套件的流程結構,能應對多變的業務需求,下面是將兩者進行結合的結構圖。

 



一個request在經過每一個handler處理單元時,會根據request的上下文內容選擇合適的策略進行處理,然後將這所有的handler串聯起來形成完整的業務流程。

5 總結

在日常程式碼的編寫中,業務需求的變化總是不定的,這樣會導致我們的程式碼會頻繁的隨著需求的改變進行調整,稍加不注意的話就會導致我們的程式碼非常臃腫和複雜,累加到一定程度後會變得難以維護,這時預先使用合適的程式碼設計模式能有效的緩解這種情況,文中描述的責任鏈和策略設計模式能有效滿足程式碼編寫的開閉原則,能更加有效的應對隨時變化的業務需求。