定義:
- 責(zé)任鏈模式將鏈中每一個(gè)節(jié)點(diǎn)都看成一個(gè)對(duì)象,并且將這些節(jié)點(diǎn)對(duì)象連成一條鏈,請(qǐng)求會(huì)沿著這條鏈進(jìn)行傳遞,直到有對(duì)象處理它為止,這使得多個(gè)對(duì)象都有機(jī)會(huì)接收請(qǐng)求,避免了請(qǐng)求發(fā)送者和接收者之間的耦合。
- 屬于行為型設(shè)計(jì)模式。
責(zé)任鏈模式的角色組成:
- Handler(抽象處理者):定義一個(gè)處理請(qǐng)求的抽象方法,并維護(hù)一個(gè)下一個(gè)處理節(jié)點(diǎn)對(duì)象的引用。
- ConcreteHandler(具體處理者):實(shí)現(xiàn)了抽象處理請(qǐng)求方法,并在處理之前進(jìn)行判斷是否有相應(yīng)的處理權(quán)限,有則處理,沒(méi)有則將請(qǐng)求轉(zhuǎn)發(fā)后繼者處理。
責(zé)任鏈模式的 UML 類(lèi)圖:
??情景案例:大家在公司上班難免遇到有事需要請(qǐng)假的情況,就我所在的公司來(lái)說(shuō),請(qǐng)假時(shí)間不超過(guò)3個(gè)工作日的,自己的直接領(lǐng)導(dǎo)(leader)可以直接審批,但是如果大于三個(gè)工作日不超過(guò)五個(gè)工作日的,則需要經(jīng)理(CommonManager)進(jìn)行審批了,而請(qǐng)假時(shí)間超過(guò)5個(gè)工作日的需要總經(jīng)理(GeneralManager)進(jìn)行審批了。其實(shí),請(qǐng)假審批流程這樣的場(chǎng)景就可以使用責(zé)任鏈模式模擬,提出的請(qǐng)假請(qǐng)求被一層層傳遞轉(zhuǎn)發(fā),直到最終的決策者。
抽象處理者 Manager:
public abstract class Manager {
protected String name;
protected Manager superior;
public Manager(String name) {
this.name = name;
}
public void setSuperior(Manager superior) {
this.superior = superior;
}
public abstract void requestAbsence(int days);
}
具體處理者 Leader:
public class Leader extends Manager{
public Leader(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days <= 3) {
System.out.println(String.format("請(qǐng)假%s天被批準(zhǔn),審核人為%s!", days, name));
} else {
if (superior != null) {
System.out.println(String.format("請(qǐng)假%s天被批準(zhǔn),審核人為%s,還需上級(jí)領(lǐng)導(dǎo)審核!", days, name));
superior.requestAbsence(days);
}
}
}
}
具體處理者 CommonManager:
public class CommonManager extends Manager{
public CommonManager(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days > 3 && days <= 5) {
System.out.println(String.format("請(qǐng)假%s天被批準(zhǔn),審核人為%s!", days, name));
} else {
if (superior != null) {
System.out.println(String.format("請(qǐng)假%s天被批準(zhǔn),審核人為%s,還需上級(jí)領(lǐng)導(dǎo)審核!", days, name));
superior.requestAbsence(days);
}
}
}
}
具體處理者 GeneralManager:
public class GeneralManager extends Manager {
public GeneralManager(String name) {
super(name);
}
@Override
public void requestAbsence(int days) {
if (days > 5) {
System.out.println(String.format("請(qǐng)假%s天被批準(zhǔn),審核人為%s!", days, name));
}
}
}
客戶(hù)端 Client:
public class Client {
public static void main(String[] args) {
Leader leader = new Leader("主管");
CommonManager commonManager = new CommonManager("經(jīng)理");
GeneralManager generalManager = new GeneralManager("總經(jīng)理");
leader.setSuperior(commonManager);
commonManager.setSuperior(generalManager);
leader.requestAbsence(6);
}
}
責(zé)任鏈模式的優(yōu)點(diǎn):
- 請(qǐng)求處理對(duì)象僅需維持一個(gè)指向其后繼者的引用,而不需要維持它對(duì)所有的候選處理者的引用,這樣的責(zé)任鏈可以簡(jiǎn)化對(duì)象的相互連接,降低耦合度。
- 鏈路結(jié)構(gòu)靈活,可以通過(guò)改變鏈路結(jié)構(gòu)動(dòng)態(tài)地新增或刪減責(zé)任。
- 易于擴(kuò)展新的請(qǐng)求處理類(lèi)(節(jié)點(diǎn)),符合開(kāi)閉原則。
責(zé)任鏈模式的缺點(diǎn):
- 責(zé)任鏈太長(zhǎng)或者處理時(shí)間過(guò)長(zhǎng),會(huì)影響整體性能。
- 如果建鏈不當(dāng),可能會(huì)造成循環(huán)調(diào)用,將導(dǎo)致系統(tǒng)陷入死循環(huán)。
- 一個(gè)請(qǐng)求也可能因職責(zé)鏈沒(méi)有被正確配置而得不到處理。
責(zé)任鏈模式的適用場(chǎng)景:
- 多個(gè)對(duì)象可以處理同一請(qǐng)求,但具體由哪個(gè)對(duì)象處理則在運(yùn)行時(shí)動(dòng)態(tài)決定。
- 在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交請(qǐng)求。
- 需要可以動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求,客戶(hù)端可以動(dòng)態(tài)創(chuàng)建責(zé)任鏈來(lái)處理請(qǐng)求,還可以改變鏈中處理者之間的先后次序。
??責(zé)任鏈模式在JDK源碼
javax.servlet
包中的應(yīng)用
Servlet API
中提供了一個(gè) Filter
(過(guò)濾器)接口,通過(guò)過(guò)濾器技術(shù),開(kāi)發(fā)人員可以實(shí)現(xiàn)用戶(hù)在訪(fǎng)問(wèn)某個(gè)目標(biāo)資源之前,對(duì)訪(fǎng)問(wèn)的請(qǐng)求和響應(yīng)進(jìn)行攔截,一般常用于實(shí)現(xiàn) URL
級(jí)別的權(quán)限訪(fǎng)問(wèn)控制、過(guò)濾敏感詞匯、壓縮響應(yīng)信息等一些高級(jí)功能。
Servlet API 中的 Filter
源碼如下:
public interface Filter {
// 過(guò)濾器第一次初始化時(shí)執(zhí)行,初始化配置參數(shù),在doFilter()方法之前被調(diào)用
default void init(FilterConfig filterConfig) throws ServletException {
}
// 在客戶(hù)端請(qǐng)求及服務(wù)器端回復(fù)時(shí)都將被自動(dòng)調(diào)用,服務(wù)器每次在調(diào)用web資源之前,都會(huì)先調(diào)用一下該方法
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
// 結(jié)束過(guò)濾器,doFilter()方法完成后被調(diào)用
default void destroy() {
}
}
Filter
相當(dāng)于責(zé)任鏈模式中的抽象處理者 Handler
,它是由 doFilter()
方法的最后一個(gè)參數(shù) FilterChain
實(shí)現(xiàn)一條責(zé)任鏈的,其源碼如下:
public interface FilterChain {
/**
* 調(diào)用鏈中的下一個(gè)過(guò)濾器,如果是調(diào)用鏈中最后一個(gè)過(guò)濾器,將調(diào)用鏈中最后一個(gè)資源
* @param request 將沿著鏈請(qǐng)求
* @param response 將沿著鏈回復(fù)
*/
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}
FilterChain
類(lèi)中只定義了一個(gè) doFilter()
方法上,J2EE 只定義了一個(gè)規(guī)范,具體處理邏輯是由使用者自己來(lái)實(shí)現(xiàn),例如 Spring 框架中的實(shí)現(xiàn) MockFilterChain
類(lèi):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-543757.html
public class MockFilterChain implements FilterChain {
@Nullable
private ServletRequest request;
@Nullable
private ServletResponse response;
private final List<Filter> filters;
@Nullable
private Iterator<Filter> iterator;
public MockFilterChain() {
this.filters = Collections.emptyList();
}
public MockFilterChain(Servlet servlet) {
this.filters = initFilterList(servlet);
}
public MockFilterChain(Servlet servlet, Filter... filters) {
Assert.notNull(filters, "filters cannot be null");
Assert.noNullElements(filters, "filters cannot contain null values");
this.filters = initFilterList(servlet, filters);
}
private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {
Filter[] allFilters = (Filter[])ObjectUtils.addObjectToArray(filters, new MockFilterChain.ServletFilterProxy(servlet));
return Arrays.asList(allFilters);
}
@Nullable
public ServletRequest getRequest() {
return this.request;
}
@Nullable
public ServletResponse getResponse() {
return this.response;
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(this.request == null, "This FilterChain has already been called!");
if (this.iterator == null) {
this.iterator = this.filters.iterator();
}
if (this.iterator.hasNext()) {
Filter nextFilter = (Filter)this.iterator.next();
nextFilter.doFilter(request, response, this);
}
this.request = request;
this.response = response;
}
public void reset() {
this.request = null;
this.response = null;
this.iterator = null;
}
private static final class ServletFilterProxy implements Filter {
private final Servlet delegateServlet;
private ServletFilterProxy(Servlet servlet) {
Assert.notNull(servlet, "servlet cannot be null");
this.delegateServlet = servlet;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
this.delegateServlet.service(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
public String toString() {
return this.delegateServlet.toString();
}
}
}
MockFilterChain
類(lèi)把鏈中的所有 Filter
都放到 List
中,然后在調(diào)用 doFilter()
方法時(shí)循環(huán)迭代List
,也就是說(shuō) List
中的 Filter
會(huì)按順序執(zhí)行。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-543757.html
到了這里,關(guān)于《設(shè)計(jì)模式》責(zé)任鏈模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!