一、概念以及背景
責(zé)任鏈模式(Chain of Responsibility Pattern):責(zé)任鏈模式是一種創(chuàng)建處理對象序列(比如操作序列)的通用方案。一個處理對象可能需要在完成一些工作之后,將結(jié)果傳遞給另一個對象,這個對象接著做一些工作,再轉(zhuǎn)交給下一個處理對象,以此類推。
簡而言之,待處理的對象,需要經(jīng)過好幾個步驟的處理,形成一條鏈,一個步驟處理完之后,接著往下一個步驟繼續(xù)處理。
本文涉及的代碼在github上,點擊 鏈接 可查看源碼。
本文會用兩種方式來實現(xiàn)責(zé)任鏈模式,第二種是用lambda表達(dá)式的方式來實現(xiàn),參數(shù)行為化的方式實現(xiàn)。
本文所使用的場景如下:處理一封信,首先對會信的頭部進(jìn)行處理,然后會檢查這份信的拼寫有無錯誤,有的話把錯誤的單詞修改過來,最后會對信的結(jié)尾進(jìn)行處理。這樣一來處理一封信就形成了一條鏈,先處理……,再處理……,最后處理……。
二、責(zé)任鏈模式
基于上面提到的場景,UML類圖如下,責(zé)任鏈模式之所以能形成鏈,其核心是有一個抽象處理類,該抽象處理類會有一個字段(抽象處理者)被用來記錄后續(xù)對象,即記錄執(zhí)行處理某個步驟的對象。然后該抽象處理類還有一個抽象方法,即handleWork抽象方法,每個處理步驟(鏈節(jié)點)都會實現(xiàn)該抽象方法,作為該步驟的處理邏輯,當(dāng)然處理完之后還需要丟給下一個鏈節(jié)點處理。

- Handler抽象類,即抽象處理類,含有一個字段是抽象處理者successor,當(dāng)然也有setSuccessor方法,用來設(shè)置下一個處理者,即本步驟/鏈節(jié)點處理完之后,傳遞給下一個處理者繼續(xù)處理。handleWork抽象方法提供了實現(xiàn)不同的處理步驟,有不同的處理邏輯,這里的handle方法也起到了不少的作用,形成鏈,本鏈節(jié)點handleWork之后,判斷自身是否還擁有下一處理者,有的話,下一處理者繼續(xù)進(jìn)行handle->handleWork直到處理結(jié)束,無處理者。
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
abstract protected String handleWork(String input);
public String handle(String input) {
//本節(jié)點處理完之后返回下一節(jié)點
String nextNode = handleWork(input);
if (successor != null) {
return successor.handle(nextNode);
}
return nextNode;
}
}
- AddHeaderHandler類,信的頭部處理器
public class AddHeaderHandler extends Handler{
@Override
protected String handleWork(String input) {
return "From Raoul, Mario and Alan: " + input;
}
}
- CheckSpellHandler類,檢查信的拼寫
public class CheckSpellHandler extends Handler{
@Override
protected String handleWork(String input) {
return input.replaceAll("labda", "lambda");
}
}
- AddFooterHandler類,信的結(jié)尾處理器
public class AddFooterHandler extends Handler{
@Override
protected String handleWork(String input) {
return input + " Kind regards";
}
}
public class ChainMain {
public static void main(String[] args) {
AddHeaderHandler addHeaderHandler = new AddHeaderHandler();
CheckSpellHandler checkSpellHandler = new CheckSpellHandler();
AddFooterHandler addFooterHandler = new AddFooterHandler();
addHeaderHandler.setSuccessor(checkSpellHandler);
checkSpellHandler.setSuccessor(addFooterHandler);
String test = addHeaderHandler.handle("labda");
System.out.println(test);
}
}
最后控制臺輸出這封處理過的信:
From Raoul, Mario and Alan: lambda Kind regards
三、責(zé)任鏈模式,行為參數(shù)化,lambda方式重構(gòu)
這里用了Java8的Function<T,R>函數(shù)式接口,方法apply輸入T類型參數(shù),返回R類型,T,R都是String類型,符合我們處理信件,輸入和輸出都是String類型。因為我們的核心在于處理信件的邏輯,故這里結(jié)合Java8函數(shù)式接口,把行為參數(shù)化,實現(xiàn)了處理信件的處理邏輯。
- Function<T,R>
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
- LambdaHandler
public class LambdaHandler {
public static Function<String, String> addHeaderHandler() {
return (input) -> "From Raoul, Mario and Alan: " + input;
}
public static Function<String, String> checkSpellHandler() {
return (input) -> input.replaceAll("labda", "lambda");
}
public static Function<String, String> addFooterHandler() {
return (input) -> input + " Kind regards";
}
}
- ChainMain
public class ChainMain {
public static void main(String[] args) {
Function<String, String> addHeaderHandler = LambdaHandler.addHeaderHandler();
Function<String, String> checkSpellHandler = LambdaHandler.checkSpellHandler();
Function<String, String> addFooterHandler = LambdaHandler.addFooterHandler();
String test = addHeaderHandler.andThen(checkSpellHandler).andThen(addFooterHandler).apply("labda");
System.out.println(test);
}
}
- 最后控制臺輸出這封處理過的信:
From Raoul, Mario and Alan: lambda Kind regards
起核心作用的是Function<T, R>接口的默認(rèn)方法andThen,除了內(nèi)置函數(shù)式接口Function<T, R>有andThen默認(rèn)方法,Consumer<T>等內(nèi)置函數(shù)式接口也是提供andThen默認(rèn)方法的,大部分是能滿足我們的需求的。
我們可以看到,andThen方法的方法參數(shù)也是一個跟自身相同的函數(shù)式接口Function<T,R>,只不過這里的泛型有下界通配符和上界通配符Function<? super R, ? extends V> after,當(dāng)然我們可以暫不用細(xì)究這個,因為我們實現(xiàn)的接口都是入?yún)⒑头祷亟Y(jié)果都是String類型。
Objects.requireNonNull(after);首先判斷傳入的參數(shù)不能為空,畢竟這是下一個處理步驟的實現(xiàn)處理邏輯,關(guān)鍵是(T t) -> after.apply(apply(t));這句代碼起了作用,這里分為兩步,第一步是先執(zhí)行自身的apply(t)方法,即在當(dāng)前步驟,先對節(jié)點進(jìn)行處理,然后返回處理結(jié)果,接著是對節(jié)點(本步驟的處理結(jié)果)進(jìn)行下一步的處理,即after.apply(apply(t))
@FunctionalInterface
public interface Function<T, R> {
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
}
當(dāng)然節(jié)點的最后一個處理步驟,我們需要在最后返回的Function<T,R>在執(zhí)行一次apply,調(diào)用最后一個處理步驟的實現(xiàn)方法,即
String test = addHeaderHandler.andThen(checkSpellHandler).andThen(addFooterHandler).apply("labda");
本文如有不足之處,請指正或者提出好的建議?????謝謝。
參考資料:《Java8實戰(zhàn)》