摘要:前言近期在做的攔截器功能,正好用到了責任鏈模式。通過官方圖就可以非常清楚的看出是一個責任鏈模式用責任鏈模式設(shè)計一個攔截器對于攔截器來說使用責任鏈模式再好不過了。設(shè)置攔截器到責任鏈中時通過反射將的值保存到各個攔截器中。
前言
近期在做 Cicada 的攔截器功能,正好用到了責任鏈模式。
這個設(shè)計模式在日常使用中頻率還是挺高的,借此機會來分析分析。
責任鏈模式先來看看什么是責任鏈模式。
引用一段維基百科對其的解釋:
責任鏈模式在面向?qū)ο蟪淌皆O(shè)計里是一種軟件設(shè)計模式,它包含了一些命令對象和一系列的處理對象。每一個處理對象決定它能處理哪些命令對象,它也知道如何將它不能處理的命令對象傳遞給該鏈中的下一個處理對象。該模式還描述了往該處理鏈的末尾添加新的處理對象的方法。
光看這段描述可能大家會覺得懵,簡單來說就是該設(shè)計模式用于對某個對象或者請求進行一系列的處理,這些處理邏輯正好組成一個鏈條。
下面來簡單演示使用與不使用責任鏈模式有什么區(qū)別和優(yōu)勢。
責任鏈模式的應(yīng)用 傳統(tǒng)實現(xiàn)假設(shè)這樣的場景:傳入了一段內(nèi)容,需要對這段文本進行加工;比如過濾敏感詞、錯別字修改、最后署上版權(quán)等操作。
常見的寫法如下:
public class Main { public static void main(String[] args) { String msg = "內(nèi)容內(nèi)容內(nèi)容" ; String result = Process.sensitiveWord() .typo() .copyright(); } }
這樣看似沒啥問題也能解決需求,但如果我還需要為為內(nèi)容加上一個統(tǒng)一的標題呢?在現(xiàn)有的方式下就不得不新增處理方法,并且是在這個客戶端(Process)的基礎(chǔ)上進行新增。
顯然這樣的擴展性不好。
責任鏈模式實現(xiàn)這時候就到了責任鏈模式發(fā)揮作用了。
該需求非常的符合對某一個對象、請求進行一系列處理的特征。
于是我們將代碼修改:
這時 Process 就是一個接口了,用于定義真正的處理函數(shù)。
public interface Process { /** * 執(zhí)行處理 * @param msg */ void doProcess(String msg) ; }
同時之前對內(nèi)容的各種處理只需要實現(xiàn)該接口即可:
public class SensitiveWordProcess implements Process { @Override public void doProcess(String msg) { System.out.println(msg + "敏感詞處理"); } } public class CopyrightProcess implements Process { @Override public void doProcess(String msg) { System.out.println(msg + "版權(quán)處理"); } } public class CopyrightProcess implements Process { @Override public void doProcess(String msg) { System.out.println(msg + "版權(quán)處理"); } }
然后只需要給客戶端提供一個執(zhí)行入口以及添加責任鏈的入口即可:
public class MsgProcessChain { private Listchains = new ArrayList<>() ; /** * 添加責任鏈 * @param process * @return */ public MsgProcessChain addChain(Process process){ chains.add(process) ; return this ; } /** * 執(zhí)行處理 * @param msg */ public void process(String msg){ for (Process chain : chains) { chain.doProcess(msg); } } }
這樣使用起來就非常簡單:
public class Main { public static void main(String[] args) { String msg = "內(nèi)容內(nèi)容內(nèi)容==" ; MsgProcessChain chain = new MsgProcessChain() .addChain(new SensitiveWordProcess()) .addChain(new TypoProcess()) .addChain(new CopyrightProcess()) ; chain.process(msg) ; } }
當我需要再增加一個處理邏輯時只需要添加一個處理單元即可(addChain(Process process)),并對客戶端 chain.process(msg) 是無感知的,不需要做任何的改動。
可能大家沒有直接寫過責任鏈模式的相關(guān)代碼,但不經(jīng)意間使用到的卻不少。
比如 Netty 中的 pipeline 就是一個典型的責任鏈模式,它可以讓一個請求在整個管道中進行流轉(zhuǎn)。
通過官方圖就可以非常清楚的看出是一個責任鏈模式:
用責任鏈模式設(shè)計一個攔截器對于攔截器來說使用責任鏈模式再好不過了。
下面來看看在 Cicada 中的實現(xiàn):
首先是定義了和上文 Process 接口類似的 CicadaInterceptor 抽象類:
public abstract class CicadaInterceptor { public boolean before(CicadaContext context,Param param) throws Exception{ return true; } public void after(CicadaContext context,Param param) throws Exception{} }
同時定義了一個 InterceptProcess 的客戶端:
其中的 loadInterceptors() 會將所有的攔截器加入到責任鏈中。
再提供了兩個函數(shù)分別對應(yīng)了攔截前和攔截后的入口:
實際應(yīng)用現(xiàn)在來看看具體是怎么使用的吧。
在請求的 handle 中首先進行加載(loadInterceptors(AppConfig appConfig)),也就是初始化責任鏈。
接下來則是客戶端的入口;調(diào)用攔截前后的入口方法即可。
由于是攔截器,那么在 before 函數(shù)中是可以對請求進行攔截的。只要返回 false 就不會繼續(xù)向后處理。所以這里做了一個返回值的判斷。
同時對于使用者來說只需要創(chuàng)建攔截器類繼承 CicadaInterceptor 類即可。
這里做了一個演示,分別有兩個攔截器:
記錄一個業(yè)務(wù) handle 的執(zhí)行時間。
在 after 里打印了請求參數(shù)。
同時可在第一個攔截器中返回 false 讓請求被攔截。
先來做前兩個試驗:
這樣當我請求其中一個接口時會將剛才的日志打印出來:
接下來我讓打印執(zhí)行時間的攔截器中攔截請求,同時輸入向前端輸入一段文本:
請求接口可以看到如下內(nèi)容:
同時后面的請求參數(shù)也沒有打印出來,說明請求確實被攔截下來。
同時我也可以調(diào)整攔截順序,只需要在 @Interceptor(order = 1) 注解中定義這個 order 屬性即可(默認值是 0,越小越先執(zhí)行)。
之前是打印請求參數(shù)的攔截器先執(zhí)行,這次我手動將它的 order 調(diào)整為 2,而打印時間的 order 為 1 。
再次請求接口觀察后臺日志:
發(fā)現(xiàn)打印執(zhí)行時間的攔截器先執(zhí)行。
那這個執(zhí)行執(zhí)行順序如何實現(xiàn)自定義配置的呢?
其實也比較簡單,有以下幾步:
在加載攔截器時將注解里的 order 保存起來。
設(shè)置攔截器到責任鏈中時通過反射將 order 的值保存到各個攔截器中。
最終通過排序重新排列這個責任鏈的順序。
貼一些核心代碼。
掃描攔截器時保存 order 值:
保存 order 值到攔截器中:
重新對責任鏈排序:
總結(jié)整個責任鏈模式已經(jīng)講完,希望對這個設(shè)計模式還不了解的朋友帶來些幫助。
上文中的源碼如下:
https://github.com/TogetherOS/cicada:一個高性能、輕量 HTTP 框架
https://git.io/fxKid
歡迎關(guān)注公眾號一起交流:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/71791.html
世界上最遙遠的距離,不是生與死,而是它從你的世界路過無數(shù)次,你卻選擇視而不見,你無情,你冷酷啊...... showImg(https://segmentfault.com/img/remote/1460000019550563); 被你忽略的就是責任鏈設(shè)計模式,希望它再次經(jīng)過你身旁你會猛的發(fā)現(xiàn),并對它微微一笑...... 責任鏈設(shè)計模式介紹 抽象介紹 初次見面,了解表象,深入交流之后(看完文中的...
摘要:推文用設(shè)計模式解構(gòu)三國是一種什么體驗行為型設(shè)計模式一策略模式工廠模式優(yōu)化結(jié)構(gòu)狀態(tài)模式隨著狀態(tài)改變而改變行為。推文狀態(tài)機與狀態(tài)模式責任鏈模式多個對象依次處理請求前者指定后者。代理模式代理針對一個對象,為了增加控制等中介雙方都是多個,為了解耦。 策略模式 選擇使用封裝好的一系列算法,可相互替換。 類比:商店[Context]買完衣服買單[Stratege](現(xiàn)金[Concrete Stra...
時間:2017年09月03日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com 教學(xué)源碼:https://github.com/zccodere/s...學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 面向切面 課程章節(jié) 概覽 AOP使用 AOP原理 AOP開源運用 課程實戰(zhàn) 課程總結(jié) 面向切面編程是一種...
摘要:提供酒店相關(guān)的接口返回該時間段有效的酒店提供航班相關(guān)的接口返回該時間段有效的航班提供一個旅行對外的接口,一次返回酒店和航班信息調(diào)用旅行外觀模式享元模式享元模式主要用于減少創(chuàng)建對象的數(shù)量,以減少內(nèi)存占用和提高性能。 組合模式(Composite pattern) 組合模式看起來就像對象組的樹形結(jié)構(gòu),一個對象里面包含一個或一組其他的對象。它是屬于結(jié)構(gòu)型模式。例如,一個公司包括很多個部門,每...
閱讀 964·2023-04-26 02:56
閱讀 9437·2021-11-23 09:51
閱讀 1850·2021-09-26 10:14
閱讀 2980·2019-08-29 13:09
閱讀 2154·2019-08-26 13:29
閱讀 571·2019-08-26 12:02
閱讀 3562·2019-08-26 10:42
閱讀 3000·2019-08-23 18:18