職責鏈模式
定義
使多個對象都可以處理一個請求,將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到其中某個對象可以處理它爲止。
結構
抽象處理類:它持有自身的一個引用,定義了一個用來處理請求的接口
具體處理類:實現了抽象處理類的接口方法,在方法內部判斷是否讓其處理請求還是放到下一個處理類來處理。
類圖
個人理解:職責鏈模式的思想是複合+轉發的方式實現的,只不過這次複合的對象是它本身,通過持有自身的引用可以使得處理類形成一個鏈,在處理方法內部判斷是否讓下一個處理類類處理還是自身來處理。
意圖:
抽象處理類:
public abstract class Handler {
public Handler chain;
public void setChain(Handler chain) {
this.chain = chain;
}
public abstract void handleRequest(int request);
}
具體處理類:
public class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(int request) {
if(request > 0 && request <= 10){
System.out.println("執行A處理方法");
} else if (chain != null) {
chain.handleRequest(request);
}
}
}
public class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(int request) {
if(request > 10 && request <= 20){
System.out.println("執行B處理方法");
} else if (chain != null) {
chain.handleRequest(request);
}
}
}
public class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(int request) {
if(request > 20){
System.out.println("執行C處理方法");
}
}
}
測試類:
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setChain(handlerB);
handlerB.setChain(handlerC);
handlerA.handleRequest(5);
handlerA.handleRequest(11);
handlerA.handleRequest(30);
}
測試結果:
案例
我們以員工申請請假需要經過領導審批爲例。組長、總監、經理作爲處理審批申請的具體處理類,它們各自持有自身的引用,通過請求中請假天數判斷由誰來處理審批流程。
抽象處理類:
public abstract class AbstractHandler {
public AbstractHandler chain;
public void setChain(AbstractHandler chain) {
this.chain = chain;
}
public abstract void handleRequest(int request);
}
組長處理類:
public class TeamLeaderHandler extends AbstractHandler {
@Override
public void handleRequest(int request) {
if(request>0&&request<=2){
System.out.println("組長同意請假"+request+"天");
}else if(chain!=null){
chain.handleRequest(request);
}
}
}
總監處理類:
public class DirectorHandler extends AbstractHandler {
@Override
public void handleRequest(int request) {
if(request>2&&request<=5){
System.out.println("總監同意請假"+request+"天");
}else if(chain!=null){
chain.handleRequest(request);
}
}
}
經理處理類:
public class ManagerHandler extends AbstractHandler{
@Override
public void handleRequest(int request) {
if(request>5){
System.out.println("經理同意請假"+request+"天");
}
}
}
測試類:
public static void main(String[] args) {
AbstractHandler teamLeader = new TeamLeaderHandler();
AbstractHandler director = new DirectorHandler();
AbstractHandler manager = new ManagerHandler();
teamLeader.setChain(director);
director.setChain(manager);
teamLeader.handleRequest(1);
teamLeader.handleRequest(3);
teamLeader.handleRequest(15);
}
測試結果:
優點
1.新增具體處理類方便靈活。
2.將請求的發送者(即客戶端)和請求的接受者(處理類)解耦合。
缺點
可能出現請求無法被處理的情況。
JDK類庫中的職責鏈模式
java.util.loggingLogger#log(LogRecord ld)(暫時還不明白這個爲什麼會使職責鏈模式!)
javax.servlet.Filter#doFilter(req,rep)
典型的例子是struts2的核心過濾器:StrutsPrepareAndExecuteFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}