1. 責任鏈模式介紹
責任鏈模式(Chain of Responsibility)是一種行為設計模式,它允許將多個處理器(處理對象)連接成一條鏈,并沿著這條鏈傳遞請求,直到有一個處理器處理它為止。職責鏈模式的主要目的是避免請求的發送者與多個請求處理者之間的耦合。
類比場景:想象一下,客戶服務中心有多個層級的客服人員:初級客服、高級客服和經理。客戶的問題會從初級客服開始,逐級向上轉發,直到有一個客服能夠解決問題。
組成結構:職責鏈模式主要包含以下幾個部分:
- 抽象處理者(Handler):定義一個處理請求的接口,并包含一個指向下一個處理者的引用。
- 具體處理者(ConcreteHandler):實現處理請求的具體邏輯,并決定是否將請求傳遞給下一個處理者。
- 處理器鏈(
HandlerChain
):?在職責鏈模式的實現中,使用HandlerChain不是必須的,但
是一種常見的做法。HandlerChain
?的使用主要是為了簡化鏈的管理,使得鏈的創建和維護更加便捷和集中。 - 客戶端(Client):負責創建處理鏈,并向鏈中的第一個處理者發送請求。
優缺點分析:
- 優點:
- 降低耦合:請求發送者和接收者之間的耦合度降低,靈活地新增和修改處理者。
- 動態組合:可以方便地改變鏈內的成員或調動它們的次序。
- 缺點:
- 不保證請求被處理:如果鏈的末端沒有處理請求,可能會導致請求不被處理。這個場景可以通過責任鏈的變體實現,讓請求被所有處理器都處理。
- 性能問題:鏈過長可能導致性能問題,因為請求需要經過多個處理者。
適用場景:
- 需要動態地指定請求的處理者。
- 有多個對象可以處理某個請求,但具體處理者不確定。
- 希望請求的發送者和接收者解耦。
2. 代碼演示
責任鏈有鏈表和列表兩種實現方式,這里分別演示。演示場景圍繞“初級客服、高級客服和經理處理客訴”展開。
2.1 鏈表實現
抽象處理者(Handler):鏈式實現方式中,抽象處理類是一個抽象類,里面定義了處理請求的接口(這里是doHandle接口),并包含指向下一個處理者的引用(這里對應nextHandler屬性)。通常還會將調用下個處理器的通用邏輯提取出來(對應handleRequest方法),這樣具體處理器類只需要實現自己的業務邏輯就可以了。
// 抽象處理者
public abstract class CustomerServiceHandler {//下一個處理器的對象protected CustomerServiceHandler nextHandler;public void setNextHandler(CustomerServiceHandler nextHandler) {this.nextHandler = nextHandler;}//調用下個處理器的邏輯,原本放在具體處理器中;屬于通用邏輯,這里利用模版模式提取到父類public void handleRequest(String request) {boolean handled = doHandle(request);//gof定義:若當前處理器不能處理,則需要向下個處理器傳遞; 否則結束if (!handled && nextHandler != null) {nextHandler.handleRequest(request);}}//抽象處理邏輯:具體實現放在各handler自己實現的 doHandle() 函數里public abstract boolean doHandle(String request);}
具體處理者(ConcreteHandler):
//具體處理者 - 初級客服
public class JuniorCustomerService extends CustomerServiceHandler {@Overridepublic boolean doHandle(String request) {if (request.equals("basic")) {System.out.println("junior customer service handle");return true;}return false;}
}// 具體處理者 - 高級客服
public class SeniorCustomerService extends CustomerServiceHandler {@Overridepublic boolean doHandle(String request) {if (request.equals("advanced")) {System.out.println("senior customer service handle");return true;}return false;}
}// 具體處理者 - 經理
public class Manager extends CustomerServiceHandler {@Overridepublic boolean doHandle(String request) {if (request.equals("complex")) {System.out.println("manager customer service handle");return true;}return false;}
}
處理器鏈(HandlerChain
):HandlerChain不是必須的,
在某些情況下,直接在客戶端代碼中構建職責鏈是足夠的,尤其是鏈簡單且變化不頻繁的時候。然而,在處理復雜鏈或需要動態調整鏈的場景下,引入?HandlerChain
?可以提高代碼的清晰度和靈活性。通過HandlerChain
集中管理handlers,負責鏈中處理者的添加、移除和遍歷,簡化鏈的管理。
public class CustomerServiceHandlerChain {private CustomerServiceHandler firstHandler;private CustomerServiceHandler lastHandler;//給鏈表中添加處理器public void addHandler(CustomerServiceHandler handler) {if (firstHandler == null) {//鏈表頭為null,放在鏈表頭firstHandler = handler;lastHandler = handler;} else {//否則放在鏈表尾lastHandler.setNextHandler(handler);lastHandler = handler;}}//執行鏈表中的處理器:從第一個處理器開始執行public void handleRequest(String request) {if (null != firstHandler) {firstHandler.handleRequest(request);}}
}
客戶端代碼:
public class CustomerServiceChainDemo {public static void main(String[] args) {CustomerServiceHandlerChain handlerChain = new CustomerServiceHandlerChain();handlerChain.addHandler(new JuniorCustomerService());handlerChain.addHandler(new SeniorCustomerService());handlerChain.addHandler(new Manager());// 測試不同請求//handlerChain.handleRequest("basic");handlerChain.handleRequest("advanced");}
}
對應的類圖:
2.2?列表實現
列表實現方式更加簡單,與鏈表實現的差異點:
- 抽象處理者(handler)改用interface (無需存儲對下一個處理者的引用)
- HandlerChain類中用列表而非鏈表來保存所有的處理器
- 在HandlerChain中,依次調用每個handler(鏈表對nextHandler的調用放在抽象處理者類中)
抽象處理者(Handler):列表實現方式中,抽象處理者是一個接口,定義處理請求的方法。
//抽象處理者
public interface CustomerServiceHandler {boolean handlerRequest(String request);
}
具體處理者(ConcreteHandler):
//具體處理者 - 初級客服
public class JuniorCustomerService implements CustomerServiceHandler {@Overridepublic boolean handlerRequest(String request) {if (request.equals("basic")) {System.out.println("junior customer service handle");return true;}return false;}
}//具體處理者 - 高級客服
public class SeniorCustomerService implements CustomerServiceHandler {@Overridepublic boolean handlerRequest(String request) {if (request.equals("advanced")) {System.out.println("senior customer service handle");return true;}return false;}
}//具體處理者 - 經理
public class Manager implements CustomerServiceHandler {@Overridepublic boolean handlerRequest(String request) {if (request.equals("complex")) {System.out.println("manager customer service handle");return true;}return false;}
}
處理器鏈(HandlerChain
):HandlerChain類中用列表而非鏈表來保存所有的處理器,并在HandlerChain的handle()函數中,依次調用每個處理器的handle()函數。
public class CustomerServiceHandlerChain {private List<CustomerServiceHandler> handlerList = new ArrayList<>();public void addHandler(CustomerServiceHandler handler) {handlerList.add(handler);}public void handleRequest(String request) {for (CustomerServiceHandler handler : handlerList) {//gof定義: 若當前處理器不能處理,則向下一個處理器傳遞; 否則結束Boolean handledResult = handler.handlerRequest(request);if (handledResult) {break;}}}
}
客戶端代碼:
public class CustomerServiceChainDemo {public static void main(String[] args) {CustomerServiceHandlerChain handlerChain = new CustomerServiceHandlerChain();handlerChain.addHandler(new JuniorCustomerService());handlerChain.addHandler(new SeniorCustomerService());handlerChain.addHandler(new Manager());// 測試不同請求handlerChain.handleRequest("basic");}
}
對應的類圖:
2.3 變體:所有handler都處理一遍
上述實現是按照gof定義:如果處理器鏈上的某個處理器能夠處理這個請求,那就不會繼續往下傳遞請求,整個流程就會結束。
職責鏈模式還有一種變體,那就是請求會被所有的處理器都處理一遍,不存在中途終止的情況。還是使用上述客服場景,假設用戶需要退款,需要 初級/高級/經理 三級客服簽字確認。
列表實現的代碼如下:
//抽象處理者
public interface CustomerServiceHandler {void handlerRequest(String request);
}
//具體處理者 - 初級客服
public class JuniorCustomerService implements CustomerServiceHandler {@Overridepublic void handlerRequest(String request) {//doSomething ...System.out.println("junior customer service handle");}
}//具體處理者 - 高級客服
public class SeniorCustomerService implements CustomerServiceHandler {@Overridepublic void handlerRequest(String request) {//doSomething ...System.out.println("senior customer service handle");}
}//具體處理者 - 經理
public class Manager implements CustomerServiceHandler {@Overridepublic void handlerRequest(String request) {//doSomething ...System.out.println("manager customer service handle");}
}
//處理器鏈
public class CustomerServiceHandlerChain {private List<CustomerServiceHandler> handlerList = new ArrayList<>();public void addHandler(CustomerServiceHandler handler) {handlerList.add(handler);}public void handleRequest(String request) {for (CustomerServiceHandler handler : handlerList) {//變體類型: 不關注 handled值,請求會被所有的處理器都處理一遍,不存在中途終止的情況handler.handlerRequest(request);}}
}
//客戶端代碼
public class CustomerServiceChainDemo {public static void main(String[] args) {CustomerServiceHandlerChain handlerChain = new CustomerServiceHandlerChain();handlerChain.addHandler(new JuniorCustomerService());handlerChain.addHandler(new SeniorCustomerService());handlerChain.addHandler(new Manager());//發起退款handlerChain.handleRequest("退款100元");}
}