詳解Java設計模式之職責鏈模式
職責鏈模式
1、職責鏈模式介紹
責任鏈模式(Chain of Responsibility Pattern)是一種行為設計模式,使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關(guān)系。將這個對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
在責任鏈模式中,請求通過一條鏈傳遞,每個對象都有機會處理請求。當一個對象無法處理請求時,它會將請求傳遞給鏈中的下一個對象,直到找到能夠處理請求的對象為止。這種方式可以動態(tài)地組織和管理對象,使得請求發(fā)送者和接收者之間解耦,提高系統(tǒng)的靈活性和可擴展性。
1.1 職責鏈模式基本實現(xiàn)
職責鏈模式結(jié)構(gòu)圖:
責任鏈模式包含以下幾個角色:
- 抽象處理者(Handler):定義了一個處理請求的接口,通常包含一個指向下一個處理者的引用,用于構(gòu)建責任鏈。
- 具體處理者(ConcreteHandler):實現(xiàn)抽象處理者接口,具體處理請求的邏輯。如果可以處理請求,則處理請求;否則,將請求傳遞給下一個處理者。
Handler類,定義一個處理請示的接口:
/** * @author Shier * CreateTime 2023/5/20 16:04 * 處理請求的接口 */ public abstract class Handler { protected Handler successor; /** * 設置繼承者 * @param successor */ public void setSuccessor(Handler successor) { this.successor = successor; } public abstract void handleRequest(int request); }
ConcreteHandler類,具體處理者類,處理它所負責的請求,可訪問它的 后繼者,如果可處理該請求,就處理之,否則就將該請求轉(zhuǎn)發(fā)給它的后繼 者。
ConcreteHandler1,當請求數(shù)為0~10則有權(quán)處理,否則轉(zhuǎn)到下一位:
/** * @author Shier * CreateTime 2023/5/20 16:06 */ public class ConcreteHandler1 extends Handler { @Override public void handleRequest(int request) { if (request >= 0 && request < 10) { // 當前處理者權(quán)限 0 ~ 9 System.out.println(this.getClass().getSimpleName() + "處理了請求" + request); } else if (successor != null) { // 轉(zhuǎn)移給下一個處理者 successor.handleRequest(request); } } }
ConcreteHandler2,當請求數(shù)為10~20則有權(quán)處理,否則轉(zhuǎn)到下一位。
/** * @author Shier * CreateTime 2023/5/20 16:06 */ public class ConcreteHandler2 extends Handler { @Override public void handleRequest(int request) { if (request >= 10 && request < 20) { // 當前處理者權(quán)限 10 ~ 19 System.out.println(this.getClass().getSimpleName() + "處理了請求" + request); } else if (successor != null) { // 轉(zhuǎn)移給下一個處理者 successor.handleRequest(request); } } }
ConcreteHandler3,當請求數(shù)為20~99則有權(quán)處理,否則轉(zhuǎn)到下一位
/** * @author Shier * CreateTime 2023/5/20 16:06 */ public class ConcreteHandler3 extends Handler { @Override public void handleRequest(int request) { if (request >= 20 && request < 100) { // 當前處理者權(quán)限 20 ~ 99 System.out.println(this.getClass().getSimpleName() + "處理了請求" + request); } else if (successor != null) { // 轉(zhuǎn)移給下一個處理者 successor.handleRequest(request); } } }
客戶端代碼,向鏈上的具體處理者對象提交請求。
/** * @author Shier * CreateTime 2023/5/20 16:09 */ public class ChainClient { public static void main(String[] args) { ConcreteHandler1 handler1 = new ConcreteHandler1(); ConcreteHandler2 handler2 = new ConcreteHandler2(); ConcreteHandler3 handler3 = new ConcreteHandler3(); // 設置職責鏈上下關(guān)系 handler1.setSuccessor(handler2); handler2.setSuccessor(handler3); // 請求 int[] request = {15, 67, 8, 9, 46, 1, 5, 23, 41}; // 循環(huán)給最小矗立著提交請求,不同的數(shù)額,得不同的權(quán)限處理者處理 for (int i : request) { handler1.handleRequest(i); } } }
2、具體例子說明
在公司請假或者升職加薪,需要通過經(jīng)理、總監(jiān)、總經(jīng)理的批準,不同身份有不同的權(quán)限。當然可以直接直接找總經(jīng)理給你升職加薪??
2.1 不使用職責鏈模式 - 加薪 / 請假
升值加薪:經(jīng)理是沒有權(quán)限的,要上報給總監(jiān),總監(jiān)的回復也是沒有權(quán)限管,只能再上報到總經(jīng)理才有處理的權(quán)限
請假:經(jīng)理只能處理請假兩天的申請,再多就不可以。必須要上報給上司才有權(quán)限去處理這個請求。
// 申請類 public class Request { // 申請類別 private String requestType; public String getRequestType(){ return this.requestType; } public void setRequestType(String value){ this.requestType = value; } //申請內(nèi)容 private String requestContent; public String getRequestContent(){ return this.requestContent; } public void setRequestContent(String value){ this.requestContent = value; } // 數(shù)量 private int number; public int getNumber(){ return this.number; } public void setNumber(int value){ this.number = value; } }
//管理者 public class Manager{ protected String name; public Manager(String name){ this.name = name; } public void getResult(String managerLevel,Request request){ if (managerLevel == "經(jīng)理"){ if (request.getRequestType()=="請假" && request.getNumber()<=2) System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"天,被批準"); else System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"天,我無權(quán)處理"); } else if (managerLevel == "總監(jiān)"){ if (request.getRequestType()=="請假" && request.getNumber()<=5) System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"天,被批準"); else System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"天,我無權(quán)處理"); } else if (managerLevel == "總經(jīng)理"){ if (request.getRequestType()=="請假") System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"天,被批準"); else if (request.getRequestType()=="加薪" && request.getNumber()<=5000) System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"元,被批準"); else if (request.getRequestType()=="加薪" && request.getNumber()>5000) System.out.println(this.name+":"+request.getRequestContent()+" 數(shù)量:"+request.getNumber()+"元,再說吧"); } } }
客戶端:
public class Test { public static void main(String[] args) { Manager manager = new Manager("金利"); Manager director = new Manager("宗劍"); Manager generalManager = new Manager("鐘精勵"); Request request = new Request(); request.setRequestType("加薪"); request.setRequestContent("Shier請求加薪"); request.setNumber(10000); // 不同身份的人有不同的權(quán)限,進行處理結(jié)果 manager.getResult("經(jīng)理", request); director.getResult("總監(jiān)", request); generalManager.getResult("總經(jīng)理", request); Request request2 = new Request(); request2.setRequestType("請假"); request2.setRequestContent("Shier請假"); request2.setNumber(3); // 權(quán)限級別 manager.getResult("經(jīng)理", request2); director.getResult("總監(jiān)", request2); generalManager.getResult("總經(jīng)理", request2); } }
通過上面的程序,會發(fā)現(xiàn)一個問題管理者類,里面的方法比較長,太多的分支判斷。類的責任太多,就違背了單一職責原則,同時增加新的項目時,要去修改這個方法,就違背了開發(fā) - 封閉原則。下面就要用到職責鏈模式要簡化這樣開發(fā)業(yè)務場景 。
2.2 職責鏈模式 - 加薪 / 請假
將上面的程序進行重構(gòu),得到的代碼結(jié)構(gòu)圖如下:
Request請求類:
/** * @author Shier * 申請類 */ public class Request { // 申請類別 private String requestType; public String getRequestType() { return this.requestType; } public void setRequestType(String value) { this.requestType = value; } //申請內(nèi)容 private String requestContent; public String getRequestContent() { return this.requestContent; } public void setRequestContent(String value) { this.requestContent = value; } // 數(shù)量 private int number; public int getNumber() { return this.number; } public void setNumber(int value) { this.number = value; } }
抽象管理者:
/** * @author Shier * CreateTime 2023/5/20 16:33 * 抽象管理這類 */ public abstract class Manager { protected String name; public Manager(String name) { this.name = name; } /** * 設置管理者上級 */ protected Manager superior; public void setSuperior(Manager superior) { this.superior = superior; } /** * 請求申請 * * @param request */ public abstract void requestApplications(Request request); }
經(jīng)理類就可以去繼承這個'管理者'類,只需重寫 '申請請求' 的方法
/** * @author Shier * CreateTime 2023/5/20 16:34 * 普通經(jīng)理類 */ public class CommonManager extends Manager { public CommonManager(String name) { super(name); } @Override public void requestApplications(Request request) { if (request.getRequestType() == "請假" && request.getNumber() <= 2) { System.out.println(this.name + ":" + request.getRequestContent() + " 數(shù)量:" + request.getNumber() + "天,被批準"); } else if (this.superior != null) { this.superior.requestApplications(request); } } }
總監(jiān)同樣繼承抽象管理類
/** * @author Shier * CreateTime 2023/5/20 16:36 * 總監(jiān) */ public class Director extends Manager { public Director(String name) { super(name); } @Override public void requestApplications(Request request) { if (request.getRequestType() == "請假" && request.getNumber() <= 5) { System.out.println(this.name + ":" + request.getRequestContent() + " 數(shù)量:" + request.getNumber() + "天,被批準"); } else if (this.superior != null) { this.superior.requestApplications(request); } } }
總經(jīng)理同樣繼承管理者類,總經(jīng)理的權(quán)限就是全部都需要處理。
/** * @author Shier * CreateTime 2023/5/20 16:36 * 總經(jīng)理 */ public class GeneralManager extends Manager { public GeneralManager(String name) { super(name); } @Override public void requestApplications(Request request) { if (request.getRequestType() == "請假") { System.out.println(this.name + ":" + request.getRequestContent() + " 數(shù)量:" + request.getNumber() + "天,被批準"); } else if (request.getRequestType() == "加薪" && request.getNumber() <= 5000) { System.out.println(this.name + ":" + request.getRequestContent() + " 數(shù)量:" + request.getNumber() + "元,被批準"); } else if (request.getRequestType() == "加薪" && request.getNumber() > 5000) { System.out.println(this.name + ":" + request.getRequestContent() + " 數(shù)量:" + request.getNumber() + "元,再說吧"); } } }
測試類:
/** * @author Shier */ public class ChainClient { public static void main(String[] args) { CommonManager manager = new CommonManager("大明經(jīng)理"); Director director = new Director("大大明總監(jiān)"); GeneralManager generalManager = new GeneralManager("大大大明總經(jīng)理"); // 設置管理者之間上下級關(guān)系 經(jīng)理 => 總監(jiān) => 總經(jīng)理 manager.setSuperior(director); director.setSuperior(generalManager); // 加薪 5000 Request request = new Request(); request.setRequestType("加薪"); request.setRequestContent("Shier請求加薪"); request.setNumber(5000); // 從自己最近的上司開始請求也就是經(jīng)理 manager.requestApplications(request); // 加薪10000 Request request1 = new Request(); request1.setRequestType("加薪"); request1.setRequestContent("Shier請求加薪"); request1.setNumber(10000); manager.requestApplications(request1); // 請假一天 Request request2 = new Request(); request2.setRequestType("請假"); request2.setRequestContent("Shier請假"); request2.setNumber(1); manager.requestApplications(request2); // 請假四天 Request request3 = new Request(); request3.setRequestType("請假"); request3.setRequestContent("Shier請假"); request3.setNumber(4); manager.requestApplications(request3); } }
最后得到的結(jié)果:
由于我們把原來的一個 '管理者' 類改成了一個抽象類和三個具體類, 此時類之間的靈活性就大大增加了,如果我們需要擴展新的管理者類別,只需要增加子類就可以。比如這個例子增加一個 '集團總裁' 類,完全是沒有問題的,只需要修改 '總經(jīng)理類' 即可,并不影響其他類代碼。
這樣使用職責鏈模式可以更加清晰這些代碼之間的關(guān)系,不像最上面的一個類里面多個判斷語句,看起來都很難維護。好了,再總結(jié)一下職責鏈模式
3、職責鏈模式總結(jié)
職責鏈模式的好處
- 當客戶提交一個請求時,請求是沿鏈傳遞直至有一個 ConcreteHandler 對象負責處理它。
- 降低耦合:接收者和發(fā)送者都沒有對方的明確信息,且鏈中的對 象自己也并不知道鏈的結(jié)構(gòu)。結(jié)果是職責鏈可簡化對象的相互連接,它們僅 需保持一個指向其后繼者的引用,而不需保持它所有的候選接受者的引用。降低了代碼之間耦合度。
- 靈活性:隨時地增加或修改處理一個請求的結(jié)構(gòu)。增強了給對象指派職責的靈活性。
優(yōu)點:
- 將請求發(fā)送者和接收者解耦,可以避免請求發(fā)送者與接收者之間的直接耦合,增強了代碼的可維護性。
- 可以動態(tài)地新增或修改請求處理順序,提高了程序的靈活性和可擴展性。
- 可以進行請求的攔截、分流等操作,方便進行統(tǒng)計和日志記錄等處理。
- 可以根據(jù)需要對請求的處理進行單獨的測試,便于代碼測試和調(diào)試。
- 解耦發(fā)送者和接收者:職責鏈模式可以將發(fā)送者和接收者解耦,發(fā)送者不需要知道請求的具體處理者是誰,而處理者也不需要知道請求的發(fā)送者是誰,從而提高系統(tǒng)的靈活性。
- 動態(tài)組合和擴展性:職責鏈模式允許動態(tài)地向鏈中添加或刪除處理者,以適應不同的業(yè)務需求,增強了系統(tǒng)的可擴展性。
- 可配置性:通過調(diào)整鏈中處理者的順序,可以靈活地配置處理流程,滿足不同的處理優(yōu)先級或條件。
缺點:
- 請求的保證:沒有明確的處理者處理請求的保證。請求可能到達鏈的末尾而沒有被處理,這需要在設計時進行合理的考慮。
- 性能考慮:由于鏈中的請求需要依次傳遞給每個處理者,因此在處理大量請求時可能會影響性能。
- 可能導致系統(tǒng)變得復雜:當鏈過長或者處理者過多時,職責鏈模式可能會導致系統(tǒng)變得復雜,難以理解和維護。
使用場景:
- 處理復雜的請求處理流程,例如購物車結(jié)算、審批流程等復雜業(yè)務中。
- 需要動態(tài)指定請求的處理順序或者動態(tài)添加新的請求處理者時。
- 處理日志記錄、緩存等攔截器的場景。例如在Spring中,就應用了責任鏈模式來實現(xiàn)Interceptor攔截器。
- 多個對象可以處理同一請求,但具體的處理者在運行時可變或不確定的情況下,可以使用職責鏈模式。
- 需要動態(tài)組合處理流程或動態(tài)調(diào)整處理順序的情況下,職責鏈模式可以提供靈活性和可配置性。
- 需要在不明確請求的發(fā)送者和接收者之間建立松耦合關(guān)系的情況下,職責鏈模式可以解耦對象之間的關(guān)系。
以上就是詳解Java設計模式之職責鏈模式的詳細內(nèi)容,更多關(guān)于Java 職責鏈模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot+Druid開啟監(jiān)控頁面的實現(xiàn)示例
本文主要介紹了SpringBoot+Druid開啟監(jiān)控頁面的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-06-06淺談springboot之JoinPoint的getSignature方法
這篇文章主要介紹了springboot之JoinPoint的getSignature方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06客戶端Socket與服務端ServerSocket串聯(lián)實現(xiàn)網(wǎng)絡通信
這篇文章主要為大家介紹了客戶端Socket與服務端ServerSocket串聯(lián)實現(xiàn)網(wǎng)絡通信的內(nèi)容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03Java利用TCP實現(xiàn)服務端向客戶端消息群發(fā)的示例代碼
這篇文章主要為大家詳細介紹了Java如何利用TCP協(xié)議實現(xiàn)服務端向客戶端消息群發(fā)功能,文中的示例代碼講解詳細,需要的可以參考下,希望對你有所幫助2022-08-08