成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

春節(jié)期間,我用責(zé)任鏈模式重構(gòu)了業(yè)務(wù)代碼

開發(fā) 前端
文章通過圖文并茂的方式幫助大家理解責(zé)任鏈設(shè)計(jì)模式,在兩種類型示例代碼以及舉例實(shí)際業(yè)務(wù)場(chǎng)景下,相信小伙伴已經(jīng)掌握了如何在合適的場(chǎng)景使用責(zé)任鏈設(shè)計(jì)模式。

 [[381655]]

本文轉(zhuǎn)載自微信公眾號(hào)「源碼興趣圈」,作者龍臺(tái)。轉(zhuǎn)載本文請(qǐng)聯(lián)系源碼興趣圈公眾號(hào)。   

前言

文章開篇,拋出一個(gè)老生常談的問題,學(xué)習(xí)設(shè)計(jì)模式有什么作用?

設(shè)計(jì)模式主要是為了應(yīng)對(duì)代碼的復(fù)雜性,讓其滿足開閉原則,提高代碼的擴(kuò)展性

另外,學(xué)習(xí)的設(shè)計(jì)模式 一定要在業(yè)務(wù)代碼中落實(shí),只有理論沒有真正實(shí)施,是無(wú)法真正掌握并且靈活運(yùn)用設(shè)計(jì)模式的

這篇文章主要說(shuō) 責(zé)任鏈設(shè)計(jì)模式,認(rèn)識(shí)此模式是在讀 Mybatis 源碼時(shí), Interceptor 攔截器主要使用的就是責(zé)任鏈,當(dāng)時(shí)讀過后就留下了很深的印象(內(nèi)心 OS:還能這樣玩)

文章先從基礎(chǔ)概念說(shuō)起,另外分析一波 Mybatis 源碼中是如何運(yùn)用的,最后按照 "習(xí)俗",設(shè)計(jì)一個(gè)真實(shí)業(yè)務(wù)場(chǎng)景上的應(yīng)用

責(zé)任鏈設(shè)計(jì)模式大綱如下:

  1. 什么是責(zé)任鏈模式
  2. 完成真實(shí)的責(zé)任鏈業(yè)務(wù)場(chǎng)景設(shè)計(jì)
  3. Mybatis Interceptor 底層實(shí)現(xiàn)
  4. 責(zé)任鏈模式總結(jié)

什么是責(zé)任鏈模式

舉個(gè)例子,SpringMvc 中可以定義攔截器,并且可以定義多個(gè)。當(dāng)一個(gè)用戶發(fā)起請(qǐng)求時(shí),順利的話請(qǐng)求會(huì)經(jīng)過所有攔截器,最終到達(dá)業(yè)務(wù)代碼邏輯,SpringMvc 攔截器設(shè)計(jì)就是使用了責(zé)任鏈模式

為什么說(shuō)順利的話會(huì)經(jīng)過所有攔截器?因?yàn)檎?qǐng)求不滿足攔截器自定義規(guī)則會(huì)被打回,但這并不是責(zé)任鏈模式的唯一處理方式,繼續(xù)往下看

在責(zé)任鏈模式中,多個(gè)處理器(參照上述攔截器)依次處理同一個(gè)請(qǐng)求。一個(gè)請(qǐng)求先經(jīng)過 A 處理器處理,然后再把請(qǐng)求傳遞給 B 處理器,B 處理器處理完后再傳遞給 C 處理器,以此類推,形成一個(gè)鏈條,鏈條上的每個(gè)處理器 各自承擔(dān)各自的處理職責(zé)

責(zé)任鏈模式中多個(gè)處理器形成的處理器鏈在進(jìn)行處理請(qǐng)求時(shí),有兩種處理方式:

  1. 請(qǐng)求會(huì)被 所有的處理器都處理一遍,不存在中途終止的情況,這里參照 MyBatis 攔截器理解
  2. 二則是處理器鏈執(zhí)行請(qǐng)求中,某一處理器執(zhí)行時(shí),如果不符合自制定規(guī)則的話,停止流程,并且剩下未執(zhí)行處理器就不會(huì)被執(zhí)行,大家參照 SpringMvc 攔截器理解

這里通過代碼的形式對(duì)兩種處理方式作出解答,方便讀者更好的理解。首先看下第一種,請(qǐng)求會(huì)經(jīng)過所有處理器執(zhí)行的情況

圖1 責(zé)任鏈模式一種實(shí)現(xiàn)

IHandler 負(fù)責(zé)抽象處理器行為,handle() 則是不同處理器具體需要執(zhí)行的方法,HandleA、HandleB 為具體需要執(zhí)行的處理器類,HandlerChain 則是將處理器串成一條鏈執(zhí)行的處理器鏈

  1. public class ChainApplication { 
  2.     public static void main(String[] args) { 
  3.         HandlerChain handlerChain = new HandlerChain(); 
  4.         handlerChain.addHandler(Lists.newArrayList(new HandlerA(), new HandlerB())); 
  5.         handlerChain.handle(); 
  6.         /** 
  7.          * 程序執(zhí)行結(jié)果: 
  8.          * HandlerA打印:執(zhí)行 HandlerA 
  9.          * HandlerB打?。簣?zhí)行 HandlerB 
  10.          */ 
  11.     } 

這種責(zé)任鏈執(zhí)行方式會(huì)將所有的 處理器全部執(zhí)行一遍,不會(huì)被打斷。Mybatis 攔截器用的正是此類型,這種類型 重點(diǎn)在對(duì)請(qǐng)求過程中的數(shù)據(jù)或者行為進(jìn)行改變

圖2 參考Mybatis攔截器實(shí)現(xiàn)

而另外一種責(zé)任鏈模式實(shí)現(xiàn),則是會(huì)對(duì)請(qǐng)求有阻斷作用,阻斷產(chǎn)生的前置條件是在處理器中自定義的,代碼中的實(shí)現(xiàn)較簡(jiǎn)單,讀者可以聯(lián)想 SpringMvc 攔截器的實(shí)現(xiàn)流程

圖3 責(zé)任鏈模式一種實(shí)現(xiàn)

根據(jù)代碼看的出來(lái),在每一個(gè) IHandler 實(shí)現(xiàn)類中會(huì)返回一個(gè)布爾類型的返回值,如果返回布爾值為 false,那么責(zé)任鏈發(fā)起類會(huì)中斷流程,剩余處理器將不會(huì)被執(zhí)行。就像我們定義在 SpringMvc 中的 Token 攔截器,如果 Token 失效就不能繼續(xù)訪問系統(tǒng),處理器將請(qǐng)求打回

  1. public class ChainApplication { 
  2.     public static void main(String[] args) { 
  3.         HandlerChain handlerChain = new HandlerChain(); 
  4.         handlerChain.addHandler(Lists.newArrayList(new HandlerA(), new HandlerB())); 
  5.         boolean resultFlag = handlerChain.handle(); 
  6.         if (!resultFlag) { 
  7.             System.out.println("責(zé)任鏈中處理器不滿足條件"); 
  8.         } 
  9.     } 

讀者可以自己在 IDEA 中實(shí)現(xiàn)兩種不同的責(zé)任鏈模式,對(duì)比其中的不同,設(shè)想下業(yè)務(wù)中真實(shí)的應(yīng)用場(chǎng)景,再或者可以跑 SpringBoot 項(xiàng)目,創(chuàng)建多個(gè)攔截器來(lái)佐證文中的說(shuō)辭

圖4 參考SpringMvc攔截器實(shí)現(xiàn)

本章節(jié)介紹了責(zé)任鏈設(shè)計(jì)模式的具體語(yǔ)義,以及不同責(zé)任鏈實(shí)現(xiàn)類型代碼舉例,并以 Mybatis、SpringMvc 攔截器為參照點(diǎn),介紹各自不同的代碼實(shí)現(xiàn)以及應(yīng)用場(chǎng)景

責(zé)任鏈業(yè)務(wù)場(chǎng)景設(shè)計(jì)

趁熱打鐵,本小節(jié)對(duì)使用的真實(shí)業(yè)務(wù)場(chǎng)景進(jìn)行舉例說(shuō)明。假設(shè)業(yè)務(wù)場(chǎng)景是這樣的,我們 系統(tǒng)處在一個(gè)下游服務(wù),因?yàn)闃I(yè)務(wù)需求,系統(tǒng)中所使用的 基礎(chǔ)數(shù)據(jù)需要從上游中臺(tái)同步到系統(tǒng)數(shù)據(jù)庫(kù)

基礎(chǔ)數(shù)據(jù)包含了很多類型數(shù)據(jù),雖然數(shù)據(jù)在中臺(tái)會(huì)有一定驗(yàn)證,但是 數(shù)據(jù)只要是人為錄入就極可能存在問題,遵從對(duì)上游系統(tǒng)不信任原則,需要對(duì)數(shù)據(jù)接收時(shí)進(jìn)行一系列校驗(yàn)

最初是要進(jìn)行一系列驗(yàn)證原則才能入庫(kù)的,后來(lái)因?yàn)楣て趩栴}只放了一套非空驗(yàn)證,趁著春節(jié)期間時(shí)間還算寬裕,把這套驗(yàn)證規(guī)則骨架放進(jìn)去

從我們系統(tǒng)的接入數(shù)據(jù)規(guī)則而言,個(gè)人覺得需要支持以下幾套規(guī)則

  1. 必填項(xiàng)校驗(yàn),如果數(shù)據(jù)無(wú)法滿足業(yè)務(wù)所必須字段要求,數(shù)據(jù)一旦落入庫(kù)中就會(huì)產(chǎn)生一系列問題
  2. 非法字符校驗(yàn),因?yàn)閿?shù)據(jù)如何錄入,上游系統(tǒng)的錄入規(guī)則是什么樣的我們都不清楚,這一項(xiàng)規(guī)則也是必須的
  3. 長(zhǎng)度校驗(yàn),理由同上,如果系統(tǒng)某字段長(zhǎng)度限制 50,但是接入來(lái)的數(shù)據(jù) 500長(zhǎng)度,這也會(huì)造成問題

為了讓讀者了解業(yè)務(wù)嵌入責(zé)任鏈模式的前因,這里列舉了三套校驗(yàn)規(guī)則,當(dāng)然真實(shí)中可能不止這三套。但是 一旦將責(zé)任鏈模式嵌入數(shù)據(jù)同步流程,就會(huì) 完全符合文初所提的開閉原則,提高代碼的擴(kuò)展性

本案例設(shè)計(jì)模式中的開閉原則通過 Spring 提供支持,后續(xù)添加新的校驗(yàn)規(guī)則就可以不必修改原有代碼

這里要再?gòu)?qiáng)調(diào)下,設(shè)計(jì)模式的應(yīng)用場(chǎng)景一定要靈活掌握,只有這樣才能在合適的業(yè)務(wù)場(chǎng)景合理運(yùn)用對(duì)象的設(shè)計(jì)模式

既然設(shè)計(jì)模式場(chǎng)景說(shuō)過了,最后說(shuō)一下需要達(dá)成的業(yè)務(wù)需求。將一個(gè)批量數(shù)據(jù)經(jīng)過處理器鏈的處理,返回出符合要求的數(shù)據(jù)分類

定義頂級(jí)驗(yàn)證接口和一系列處理器實(shí)現(xiàn)類沒什么難度,但是應(yīng)該如何進(jìn)行鏈?zhǔn)秸{(diào)用呢?

這一塊代碼需要有一定 Spring 基礎(chǔ)才能理解,一起來(lái)看下 VerifyHandlerChain 如何將所有處理器串成一條鏈

VerifyHandlerChain 處理流程如下:

  1. 實(shí)現(xiàn)自 InitializingBean 接口,在對(duì)應(yīng)實(shí)現(xiàn)方法中獲取 IOC 容器中類型為 VerifyHandler 的 Bean,也就是 EmptyVerifyHandler、SexyVerifyHandler
  2. 將 VerifyHandler 類型的 Bean 添加到處理器鏈容器中
  3. 定義校驗(yàn)方法 verify(),對(duì)入?yún)?shù)據(jù)展開處理器鏈的全部調(diào)用,如果過程中發(fā)現(xiàn)已無(wú)需要驗(yàn)證的數(shù)據(jù),直接返回

這里使用 SpringBoot 項(xiàng)目中默認(rèn)測(cè)試類,來(lái)測(cè)試一下如何調(diào)用

  1. @SpringBootTest 
  2. class ChainApplicationTests { 
  3.  
  4.     @Autowired 
  5.     private VerifyHandlerChain verifyHandlerChain; 
  6.  
  7.     @Test 
  8.     void contextLoads() { 
  9.         List<Object> verify = verifyHandlerChain.verify(Lists.newArrayList("源碼興趣圈""@龍臺(tái)")); 
  10.         System.out.println(verify); 
  11.     } 

這樣的話,如果客戶或者產(chǎn)品提校驗(yàn)相關(guān)的需求時(shí),我們只需要實(shí)現(xiàn) VerifyHandler 接口新建個(gè)校驗(yàn)規(guī)則實(shí)現(xiàn)類就 OK 了,這樣符合了設(shè)計(jì)模式的原則:滿足開閉原則,提高代碼的擴(kuò)展性

熟悉之前作者寫過設(shè)計(jì)模式的文章應(yīng)該知道,強(qiáng)調(diào)設(shè)計(jì)模式重語(yǔ)義,而不是具體的實(shí)現(xiàn)過程。所以,你看咱們這個(gè)校驗(yàn)代碼,把責(zé)任鏈兩種模式結(jié)合了使用

上面的代碼只是示例代碼,實(shí)際業(yè)務(wù)中的實(shí)現(xiàn)要比這復(fù)雜很多,比如:

  1. 如何定義處理器的先后調(diào)用順序。比如說(shuō)某一個(gè)處理器執(zhí)行時(shí)間很長(zhǎng)并且過濾數(shù)據(jù)很少,所以希望把它放到最后面執(zhí)行
  2. 這是為當(dāng)前業(yè)務(wù)的所有數(shù)據(jù)類型進(jìn)行過濾,如何自定義單個(gè)數(shù)據(jù)類型過濾。比如你接入學(xué)生數(shù)據(jù),學(xué)號(hào)有一定校驗(yàn)規(guī)則,這種處理器類肯定只適合單一類型

還有很多的業(yè)務(wù)場(chǎng)景,所以設(shè)計(jì)模式強(qiáng)調(diào)的應(yīng)該是一種思想,而不是固定的代碼寫法,需要結(jié)合業(yè)務(wù)場(chǎng)景靈活變通

責(zé)任鏈模式的好處

一定要使用責(zé)任鏈模式么?不使用能不能完成業(yè)務(wù)需求?

回答是肯定可以,設(shè)計(jì)模式只是幫助減少代碼的復(fù)雜性,讓其滿足開閉原則,提高代碼的擴(kuò)展性。如果不使用同樣可以完成需求

如果不使用責(zé)任鏈模式,上面說(shuō)的真實(shí)同步場(chǎng)景面臨兩個(gè)問題

  1. 如果把上述說(shuō)的代碼邏輯校驗(yàn)規(guī)則寫到一起,毫無(wú)疑問這個(gè)類或者說(shuō)這個(gè)方法函數(shù)奇大無(wú)比。減少代碼復(fù)雜性一貫方法是:將大塊代碼邏輯拆分成函數(shù),將大類拆分成小類,是應(yīng)對(duì)代碼復(fù)雜性的常用方法。如果此時(shí)說(shuō):可以把不同的校驗(yàn)規(guī)則拆分成不同的函數(shù),不同的類,這樣不也可以滿足減少代碼復(fù)雜性的要求么。這樣拆分是能解決代碼復(fù)雜性,但是這樣就會(huì)面臨第二個(gè)問題
  2. 開閉原則:添加一個(gè)新的功能應(yīng)該是,在已有代碼基礎(chǔ)上擴(kuò)展代碼,而非修改已有代碼。大家設(shè)想一下,假設(shè)你寫了三套校驗(yàn)規(guī)則,運(yùn)行過一段時(shí)間,這時(shí)候領(lǐng)導(dǎo)讓加第四套,是不是要在原有代碼上改動(dòng)

綜上所述,在合適的場(chǎng)景運(yùn)用適合的設(shè)計(jì)模式,能夠讓代碼設(shè)計(jì)復(fù)雜性降低,變得更為健壯。朝更遠(yuǎn)的說(shuō)也能讓自己的編碼設(shè)計(jì)能力有所提高,告別被人吐槽的爛代碼...

Mybatis Interceptor底層實(shí)現(xiàn)

上面說(shuō)了那么多,框架底層源碼是怎么設(shè)計(jì)并且使用責(zé)任鏈模式的?之前在看 Mybatis 3.4.x 源碼時(shí)了解到 Interceptor 底層實(shí)現(xiàn)就是責(zé)任鏈模式,這里和讀者分享 Interceptor 具體實(shí)現(xiàn)

開門見山,直接把視線聚焦到 Mybatis 源碼,版本號(hào) 3.4.7-SNAPSHOT

熟悉么?是不是和我們上面用到的責(zé)任鏈模式差不太多,有處理器集合 interceptors,有添加處理器方法

Mybatis Interceptor 不僅用到了責(zé)任鏈,還用到了動(dòng)態(tài)代理,服務(wù)于 Mybatis 四大 "護(hù)教法王",在創(chuàng)建對(duì)象時(shí)通過動(dòng)態(tài)代理和責(zé)任鏈相結(jié)合組裝而成插件模塊

  1. ParameterHandler
  2. ResultSetHandler
  3. StatementHandler
  4. Executor

使用過 Mybatis 的讀者應(yīng)該知道,查詢 SQL 的分頁(yè)語(yǔ)句就是使用 Interceptor 實(shí)現(xiàn),比如市場(chǎng)上的 PageHelper、Mybatis-Plus 分頁(yè)插件再或者我們自實(shí)現(xiàn)的分頁(yè)插件(應(yīng)該沒有項(xiàng)目組使用顯示調(diào)用多條語(yǔ)句組成分頁(yè)吧)

拿查詢語(yǔ)句舉例,如果定義了多個(gè)查詢相關(guān)的攔截器,會(huì)先經(jīng)過攔截器的代碼加工,所有的攔截器執(zhí)行完畢后才會(huì)走真正查詢數(shù)據(jù)庫(kù)操作

扯的話就扯遠(yuǎn)了,能夠知道如何用、在哪用就可以了。通過 Interceptor 也能知道一點(diǎn),想要讀框架源碼,需要一定的設(shè)計(jì)模式基礎(chǔ)。如果對(duì)責(zé)任鏈、動(dòng)態(tài)代理不清楚,那么就不能理解這一塊的精髓

結(jié)言

文章通過圖文并茂的方式幫助大家理解責(zé)任鏈設(shè)計(jì)模式,在兩種類型示例代碼以及舉例實(shí)際業(yè)務(wù)場(chǎng)景下,相信小伙伴已經(jīng)掌握了如何在合適的場(chǎng)景使用責(zé)任鏈設(shè)計(jì)模式

看完文章后可以結(jié)合 Mybatis、SpringMvc 攔截器更深入掌握責(zé)任鏈模式的應(yīng)用場(chǎng)景以及使用手法。另外可以結(jié)合項(xiàng)目中實(shí)際業(yè)務(wù)場(chǎng)景靈活使用,相信真正使用后的你會(huì)對(duì)責(zé)任鏈模式產(chǎn)生更深入的了解

文章參考:《設(shè)計(jì)模式之美:職責(zé)鏈模式》

 

 

責(zé)任編輯:武曉燕 來(lái)源: 源碼興趣圈
相關(guān)推薦

2021-12-24 07:50:45

責(zé)任鏈模式設(shè)計(jì)

2012-03-28 13:28:56

Java設(shè)計(jì)模式

2022-12-28 08:08:57

2024-12-03 15:52:45

責(zé)任鏈Java

2022-11-01 08:46:20

責(zé)任鏈模式對(duì)象

2016-02-16 10:42:34

2024-03-04 10:36:39

2010-04-01 09:10:03

PHP設(shè)計(jì)模式責(zé)任鏈模式

2021-07-14 10:08:30

責(zé)任鏈模式加工鏈

2024-01-30 13:15:00

設(shè)計(jì)模式責(zé)任鏈

2023-09-28 08:45:56

開源責(zé)任鏈模式

2021-06-05 17:59:00

責(zé)任鏈模式設(shè)計(jì)

2021-06-09 07:15:15

責(zé)任鏈模式漲薪

2024-06-04 13:11:52

Python行為設(shè)計(jì)模式開發(fā)

2023-09-26 00:27:07

設(shè)計(jì)模式鏈接

2013-08-05 15:49:38

電商

2021-05-25 09:00:52

責(zé)任鏈模式設(shè)計(jì)模式面試經(jīng)歷

2021-02-10 15:58:09

比特幣加密貨幣區(qū)塊鏈

2022-07-04 07:37:51

模板模式重構(gòu)

2023-06-05 07:55:31

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 色综合久久久久 | 国产一区二区视频免费在线观看 | 国产精品久久久av | 午夜成人免费视频 | 日韩av在线免费 | 欧美日韩欧美 | 欧美一级视频 | 久久久亚洲一区 | 国产精品不卡一区 | 日本在线观看视频 | 欧美国产精品一区二区三区 | 天天影视网天天综合色在线播放 | 91国内精品 | 国产99久久久国产精品 | 一区日韩| 国产一级片一区二区三区 | www.亚洲区| 亚洲国产成人av好男人在线观看 | 日韩欧美网 | 欧美一级欧美三级在线观看 | 久久久久久久久久久91 | 91精品国产高清久久久久久久久 | 国产真实乱对白精彩久久小说 | 亚洲最大的成人网 | 国产精品久久久久久久久免费桃花 | 日本人做爰大片免费观看一老师 | 黄网站免费在线看 | 日韩小视频在线 | 综合激情网 | 久在线 | 激情六月天 | 成人综合视频在线观看 | 综合五月 | 亚洲国产偷 | 福利视频三区 | 国产精品小视频在线观看 | 亚洲视频一区二区三区 | 精品国产一区二区三区久久久久久 | 精品三区 | 伊人在线 | 欧美一区二区成人 |