設計模式系列文章 |
java設計模式解析(1) Observer觀察者模式
java設計模式解析(2) Proxy代理模式
java設計模式解析(3) Factory工廠模式
java設計模式解析(4) Singleton單例模式
java設計模式解析(5) Delegate委派模式
java設計模式解析(6) Strategy策略模式
java設計模式解析(7) Prototype原型模式
java設計模式解析(8) Template模版模式
java設計模式解析(9) Decorator裝飾模式
java設計模式解析(10) Adapter適配模式
java設計模式解析(11) Chain責任鏈模式 |
主要內容 |
2、實現代碼(Talk is cheap,Show me the code)
Chain責任鏈模式在《設計模式之禪》定義: 使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關系。將這些對象連成一條線,並沿着這條鏈傳遞該請求,直至有對象處理它為止。
責任鏈的核心在“鏈”,由“鏈”上所有的成員去處理請求並返回結果。 類圖中各個角色定義如下:
- Client:客戶端向發起請求,責任鏈對客戶端透明
- Handler:責任鏈抽象類,負責定義處理邏輯以及組裝責任鏈機制
- ConcreteHandler:責任鏈中的鏈由多個ConcreteHandler組裝而成
結合上述給偽碼:
==> Handler類
1 public abstract class Handler { 2 private Handler nextHandler ; 3 4 public final Response handlerMessage(Request request){ 5 Response response = null ; 6 // 符合自己處理 7 if(this.getHandlerLevel().equals(request.getRequestLevel())){ 8 response = this.echo(request) ; 9 } 10 // 交由其他人處理 11 else if (nextHandler != null) { 12 response = nextHandler.handlerMessage(request) ; 13 } 14 return response ; 15 } 16 17 // 組裝責任鏈 18 public void setNextHandler(Handler nextHandler) { 19 this.nextHandler = nextHandler; 20 } 21 22 // 模版方法 由具體的責任鏈實現者定義 23 protected abstract Level getHandlerLevel(); 24 protected abstract Response echo(Request request); 25 }
==> ConcreteHandler1、ConcreteHandler2、ConcreteHandler3三個類代碼類似,都是實際責任鏈一員且通過繼承Handler只需要實現自己的邏輯部分。
1 public class ConcreteHandler1 extends Handler { 2 @Override 3 protected Level getHandlerLevel() { 4 return null; 5 } 6 7 @Override 8 protected Response echo(Request request) { 9 return null; 10 } 11 }
==> Client客戶端發起請求 此時包含了責任鏈的組裝和調用 實際可以增加代理簡化Client操作
1 public class Client { 2 public static void main(String[] args) { 3 4 // 組裝責任鏈 5 ConcreteHandler1 handler1 = new ConcreteHandler1() ; 6 ConcreteHandler2 handler2 = new ConcreteHandler2() ; 7 ConcreteHandler3 handler3 = new ConcreteHandler3() ; 8 handler1.setNextHandler(handler2); 9 handler2.setNextHandler(handler3); 10 11 // 發起調用 12 Response response = handler1.handlerMessage(new Request()) ; 13 }
以上偽碼顯示責任鏈模式基本代碼實現,然后實際會依據情況有很多變化。如每個鏈條只處理部分數據並交由后鏈條執行,直至責任鏈的終止,甚至可以沒有任何返回結果,接下來小節將展示一個自動組裝的責任鏈demo。
2、實現代碼(Talk is cheap,Show me the code)
根據責任鏈模式設計細想,在服務提供的前置增加一個責任鏈,以完成參數校驗、簽名、日志、監控、追蹤等通用的任務。對於客戶端完全透明,對於服務端利用JAVA SPI機制(DUBBO SPI思想)靈活組裝配置責任鏈,而如果結合上強大的spring Bean容器,很容易完成服務框架的定制工作。
下面demo示例:
- Chain: 基本責任鏈中的鏈條定義
- ChainHandler:負責責任鏈的組裝和調用邏輯
- ChainLoader:利用JAVA SPI機制,加載具體責任鏈實現

1 public interface Process<T> { 2 T doProcess() ; 3 }

1 package com.nancy.chain.auto; 2 3 4 public interface Chain { 5 int HIGHEST_ORDER = Integer.MIN_VALUE ; 6 int LOWEREST_ORDER = Integer.MAX_VALUE ; 7 8 /** 9 * 處理邏輯 10 * @param chainHandler 責任鏈組裝 11 * @param pos 下一個觸發下標 12 * @param process 實際處理邏輯 13 * @return T 返回結果 14 */ 15 <T> T doChain(ChainHandler chainHandler, int pos, Process<T> process) ; 16 17 /** 18 * 配置等級 越高優先級(越小) 越優先觸發 19 * @param 20 * @return 21 */ 22 default Integer getOrder() { 23 return HIGHEST_ORDER ; 24 } 25 26 }

1 public abstract class AbstractChain implements Chain, Cloneable { 2 3 }

1 public class ChainHandler extends AbstractChain { 2 3 private List<Chain> chains ; 4 5 public ChainHandler(List<Chain> chains){ 6 this.chains = chains ; 7 chains.sort(Comparator.comparingInt(Chain::getOrder)); 8 } 9 10 private boolean hasNext(int pos){ 11 return chains.size()-1 >= pos ; 12 } 13 14 public List<Chain> getChains() { 15 return chains; 16 } 17 18 public void setChains(List<Chain> chains) { 19 this.chains = chains; 20 } 21 22 @Override 23 public <T> T doChain(ChainHandler chainHandler, int pos, Process<T> process) { 24 if(hasNext(pos)) return chainHandler.getChains().get(pos).doChain(chainHandler, ++pos, process); 25 return process.doProcess(); 26 } 27 }

1 public class ChainLoader { 2 3 public static List<Chain> loadChain(){ 4 List<Chain> chains = new ArrayList<>() ; 5 ServiceLoader<Chain> serviceLoader = ServiceLoader.load(Chain.class); 6 serviceLoader.forEach(chains::add); 7 return chains ; 8 } 9 }

1 package com.nancy.chain.auto.impl; 2 3 import com.nancy.chain.auto.AbstractChain; 4 import com.nancy.chain.auto.Chain; 5 import com.nancy.chain.auto.ChainHandler; 6 import com.nancy.chain.auto.Process; 7 import java.util.List; 8 9 public class HelloChain extends AbstractChain { 10 11 @Override 12 public <T> T doChain(ChainHandler chainHandler, int pos, Process<T> process) { 13 System.out.println("HelloChain被觸發了"); 14 return chainHandler.doChain(chainHandler, pos, process); 15 } 16 17 @Override 18 public Integer getOrder() { 19 return LOWEREST_ORDER-1 ; 20 } 21 22 } 23 24 package com.nancy.chain.auto.impl; 25 import com.nancy.chain.auto.AbstractChain; 26 import com.nancy.chain.auto.ChainHandler; 27 import com.nancy.chain.auto.Process; 28 29 public class LogChain extends AbstractChain { 30 31 @Override 32 public <T> T doChain(ChainHandler chainHandler, int pos, Process<T> process) { 33 System.out.println("LogChain被觸發了"); 34 return chainHandler.doChain(chainHandler, pos, process); 35 } 36 37 @Override 38 public Integer getOrder() { 39 return LOWEREST_ORDER ; 40 } 41 42 }
JAVA SPI機制中的文件: META-INF/services/
com.nancy.chain.auto.impl.HelloChain
com.nancy.chain.auto.impl.LogChain
觸發責任鏈:
package com.nancy.chain.auto; import com.nancy.chain.auto.spi.ChainLoader; import java.util.List; public class Main { public static void main(String[] args) { // 加載實現類 List<Chain> chains = ChainLoader.loadChain() ; // 觸發 ChainHandler handler = new ChainHandler(chains) ; Object res = handler.doChain(handler, 0, (Process<Object>) () -> 100) ; // 結果 System.out.println("結果" + res); } }
結果:
HelloChain被觸發了
LogChain被觸發了
結果100
- 責任鏈模式會依據情況有很多變化。可以只由某個“鏈條”處理請求,或者每個鏈條只處理部分數據並交由后鏈條執行,直至責任鏈的終止。可以有結果返回或者沒有任何返回結果。
- 責任鏈模式可以解耦客戶端和服務端,方便進行邏輯疊加。與觀察者模式最大不同在於前者觀察者是相互對等,之間沒有影響。而后者由鏈條串聯成線,鏈條之間可以建立起邏輯關系,完成某個功能。
- 責任鏈模式當“鏈條”很長的時候會存在很大性能問題,設計之初應該考慮長度問題,長度限制在一定范圍內。 而責任鏈之間大多具有邏輯關系,不適用類似觀察者模式用異步線程處理的方式。

