【New責任鏈&裝飾者】 感慨一下,本以為上下篇能一起發呢,結果要隔一定時間,傳統的責任鏈與裝飾者模式:https://www.cnblogs.com/SharePointApp/p/10340578.html 基本代碼 現在要做的就是責任鏈如果使用外置模式,能不能像裝飾者一樣幾個處理類聯合處理?答 ...
【New責任鏈&裝飾者】
感慨一下,本以為上下篇能一起發呢,結果要隔一定時間,傳統的責任鏈與裝飾者模式:https://www.cnblogs.com/SharePointApp/p/10340578.html
基本代碼
現在要做的就是責任鏈如果使用外置模式,能不能像裝飾者一樣幾個處理類聯合處理?答案是可以的,不過就用到java8的特性,具體代碼如下
1 //簡化的上下文 2 public class Context { 3 String handlerResult; 4 } 5 6 //處理介面 7 public interface IHandler { 8 void handler(Context context); 9 }介面與上下文
1 //預設Null介面實現 2 public class NullHandler implements IHandler { 3 @Override 4 public void handler(Context context) { 5 6 } 7 }預設Null介面實現
1 //介面的鏈式結構 2 public interface IMiddleware { 3 IHandler handle(IHandler handler); 4 }介面的鏈式結構
1 //構建鏈式結構 2 public class MiddlewareCenter { 3 private ArrayList<IMiddleware> middlewares = new ArrayList<>(); 4 5 public void userMiddleware(IMiddleware middleware) { 6 middlewares.add(middleware); 7 } 8 9 public void use(IHandler handler) { 10 this.userMiddleware(currenthandler -> { 11 return context -> { 12 handler.handler(context); 13 currenthandler.handler(context); 14 }; 15 }); 16 } 17 18 public void run(IHandler handler) { 19 this.userMiddleware(currenthandler -> { 20 return context -> { 21 handler.handler(context); 22 }; 23 }); 24 } 25 26 public IHandler build() { 27 IHandler handler = new NullHandler(); 28 Collections.reverse(middlewares); 29 for (IMiddleware middlerware : middlewares) { 30 handler=middlerware.handle(handler); 31 } 32 return handler; 33 } 34 }【重點】-鏈式結構的構建
下麵貼的是測試代碼,略顯冗長
1 public class Executor { 2 public static void main(String[] args){ 3 Context context=new Context(); 4 context.handlerResult=""; 5 MiddlewareCenter center=new MiddlewareCenter(); 6 center.use(Executor::addString); 7 center.use(Executor::addString2); 8 center.use(Executor::modifyString); 9 center.build().handler(context); 10 System.out.println(context.handlerResult); 11 12 Context context1=new Context(); 13 context1.handlerResult=""; 14 MiddlewareCenter center1=new MiddlewareCenter(); 15 center1.use(Executor::addString); 16 center1.use(Executor::modifyString); 17 center1.use(Executor::addString2); 18 center1.build().handler(context1); 19 System.out.println(context1.handlerResult); 20 21 Context context2=new Context(); 22 context2.handlerResult=""; 23 MiddlewareCenter center2=new MiddlewareCenter(); 24 center2.use(Executor::addString); 25 center2.run(Executor::modifyString); 26 center2.use(Executor::addString2); 27 center2.build().handler(context2); 28 System.out.println(context2.handlerResult); 29 } 30 31 private static void addString(Context context){ 32 context.handlerResult=context.handlerResult+"addString;"; 33 } 34 35 private static void addString2(Context context){ 36 context.handlerResult=context.handlerResult+"addString2;"; 37 } 38 39 private static void modifyString(Context context){ 40 context.handlerResult=context.handlerResult.replace("addString","addString->modifyString"); 41 } 42 }
執行結果如下:
代碼解析
先說說好處:
- 在Java8中,lamada表達式以及方法已經是一類公民,可以減少很多不必要的子類擴展。所以在組裝的時候IHandler對象的時候,沒有必要構建很多IHandler對象(傳統的責任鏈、裝飾者模式也可以,利用lamada表達式)。
- 在MiddleWareCenter中,可以直接將IHandler對象組裝在一起,和責任鏈模式外置類似,但是也可以用IMiddleWare對象,使用內置的方式將IHandler組裝起來。使代碼有很大的靈活性。
- 總的說來就是使用的時候既簡單,又強大,還有代碼看起來更時髦。
缺點呢?
- 相比於責任鏈內置、責任鏈外置、裝飾者模式,沒有什麼缺點,不過代碼略有一點難以理解
核心代碼解析
1 public IHandler build() { 2 IHandler handler = new NullHandler(); 3 Collections.reverse(middlewares); 4 for (IMiddleware middlerware : middlewares) { 5 handler=middlerware.handle(handler); 6 } 7 return handler; 8 }
這句代碼可能是最難以理解的,我們知道middlewares的類型是IArrayList<IMiddleWare>,所以這段代碼就是翻轉集合,之後遍歷組裝。怎麼遍歷組裝的,就得用數學知識進行簡單的講解了
我們知道IMiddleWare的handler方法是一個IHandler到IHandler的函數(略思考,這沒難度),我們將IHandler用自變數X代替,所以IArrayList<IMiddleWare>就是函數F(X)的集合(假設裡面的函數是A(X)、B(X)、C(X))。
翻轉集合之後,遍歷組裝的結果是C(B(A(X))),這是一個複合函數,但是本質上還是一個F(X),即IHandler到IHandler的函數。而IHandler到IHandler的函數,我們給X的值就是NullHandler,所以帶入複合函數C(B(A(X)))後得到C(B(A(NullHandler)))。這個結果是一個IHandler對象,他可以用於處理Context上下文。
哎,感覺數學還是要學好,雖然你可以不懂,但是底層都有數學基礎做支撐的。另外設計模式看類圖已經沒那麼實用了,因為方法成為第一等公民後,函數編程已經來臨,大部分設計模式可能都會有新的表述。