Java設(shè)計模式之責(zé)任鏈模式詳解
責(zé)任鏈(Chain of Responsibility)模式的定義:為了避免請求發(fā)送者與多個請求處理者耦合在一起,于是將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當(dāng)有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。
責(zé)任鏈模式的結(jié)構(gòu)
抽象處理者(Handler) 角色:定義一個處理請求的接口,包含抽象處理方法和一個后繼連接。
具體處理者(Concrete Handler)角色:實現(xiàn)抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉(zhuǎn)給它的后繼者。
客戶類(Client) 角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關(guān)心處理細(xì)節(jié)和請求的傳遞過程。
應(yīng)用場景
- 多條件流程判斷權(quán)限控制。
- ERP系統(tǒng) 流程審批:總經(jīng)理、人事經(jīng)理、項目經(jīng)理。
- Java過濾器的底層實現(xiàn)Filter
- 多個對象可以處理一個請求,但具體由哪個對象處理該請求在運(yùn)行時自動確定。
- 可動態(tài)指定一組對象處理請求,或添加新的處理者。
- 需要在不明確指定請求處理者的情況下,向多個處理者中的一個提交請求。
優(yōu)缺點
優(yōu)點
- 降低了對象之間的耦合度。該模式使得一個對象無須知道到底是哪一個對象處理其請求以及鏈的結(jié)構(gòu),發(fā)送者和接收者也無須擁有對方的明確信息。
- 增強(qiáng)了系統(tǒng)的可擴(kuò)展性??梢愿鶕?jù)需要增加新的請求處理類,滿足開閉原則。
- 增強(qiáng)了給對象指派職責(zé)的靈活性。當(dāng)工作流程發(fā)生變化,可以動態(tài)地改變鏈內(nèi)的成員或者調(diào)動它們的次序,也可動態(tài)地新增或者刪除責(zé)任。
- 責(zé)任鏈簡化了對象之間的連接。每個對象只需保持一個指向其后繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的
if
或者if.else
語句。 - 責(zé)任分擔(dān)。每個類只需要處理自己該處理的工作,不該處理的傳遞給下一個對象完成,明確各類的責(zé)任范圍,符合類的單一職責(zé)原則。
缺點
- 不能保證每個請求一定被處理。 由于一個請求沒有明確的接收者,所以不能保證它-定會被處理,該請求可能一直傳到鏈的末端都得不到處理。
- 對比較長的職責(zé)鏈,請求的處理可能涉及多個處理對象,系統(tǒng)性能將受到一定影響。
- 職責(zé)鏈建立的合理性要靠客戶端來保證,增加了客戶端的復(fù)雜性,可能會由于職責(zé)鏈的錯誤設(shè)置而導(dǎo)致系統(tǒng)出錯,如可能會造成循環(huán)調(diào)用。
代碼案例
請假條對象
public class LeaveRequest { private String name;//姓名 private int num;//請假天數(shù) private String content;//請假內(nèi)容 public LeaveRequest(String name, int num, String content) { this.name = name; this.num = num; this.content = content; } public String getName() { return name; } public int getNum() { return num; } public String getContent() { return content; } }
處理者抽象類
public abstract class Handler { protected final static int NUM_ONE = 1; protected final static int NUM_THREE = 3; protected final static int NUM_SEVEN = 7; //該領(lǐng)導(dǎo)處理的請假天數(shù)區(qū)間 private int numStart; private int numEnd; //領(lǐng)導(dǎo)上面還有領(lǐng)導(dǎo) private Handler nextHandler; //設(shè)置請假天數(shù)范圍 上不封頂 public Handler(int numStart) { this.numStart = numStart; } //設(shè)置請假天數(shù)范圍 public Handler(int numStart, int numEnd) { this.numStart = numStart; this.numEnd = numEnd; } //設(shè)置上級領(lǐng)導(dǎo) public void setNextHandler(Handler nextHandler){ this.nextHandler = nextHandler; } //提交請假條 public final void submit(LeaveRequest leave){ if(0 == this.numStart){ return; } //如果請假天數(shù)達(dá)到該領(lǐng)導(dǎo)者的處理要求 if(leave.getNum() >= this.numStart){ this.handleLeave(leave); //如果還有上級 并且請假天數(shù)超過了當(dāng)前領(lǐng)導(dǎo)的處理范圍 if(null != this.nextHandler && leave.getNum() > numEnd){ this.nextHandler.submit(leave);//繼續(xù)提交 } else { System.out.println("流程結(jié)束"); } } } //各級領(lǐng)導(dǎo)處理請假條方法 protected abstract void handleLeave(LeaveRequest leave); }
繼承抽象類實現(xiàn)責(zé)任鏈中各個類中的處理方法
public class Counselor extends Handler { public Counselor() { //輔導(dǎo)員 處理1-3天的請假 super(Handler.NUM_ONE, Handler.NUM_THREE); } @Override protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "請假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("輔導(dǎo)員審批:同意。"); //也可以在這里設(shè)置下一個鏈路處理的handler //setNextHandler(new Dean()); } } public class Dean extends Handler { public Dean() { //院長處理3-7天的請假 super(Handler.NUM_THREE, Handler.NUM_SEVEN); } @Override protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "請假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("院長審批:同意。"); //也可以在這里設(shè)置下一個鏈路處理的handler //setNextHandler(new CollegeSecretary ()); } } public class CollegeSecretary extends Handler { public CollegeSecretary() { //學(xué)院書記處理7天以上的請假 super(Handler.NUM_SEVEN); } @Override protected void handleLeave(LeaveRequest leave) { System.out.println(leave.getName() + "請假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("學(xué)院書記審批:同意。"); //也可以在這里設(shè)置下一個鏈路處理的handler //setNextHandler(null); //最后一個 } }
測試類
public class TestClient { public static void main(String[] args) { //請假條來一張 LeaveRequest leave = new LeaveRequest("kaico",8,"身體不適"); //各級領(lǐng)導(dǎo) Counselor counselor= new Counselor(); //如果前面handleLeave 方法中設(shè)置了下一個handler,這里就不需要了,直接提交申請就好了 Dean dean = new Dean(); CollegeSecretary collegeSecretary = new CollegeSecretary(); counselor.setNextHandler(dean);//輔導(dǎo)員的領(lǐng)導(dǎo)是院長 dean.setNextHandler(collegeSecretary);//院長的領(lǐng)導(dǎo)是學(xué)院書記 //提交申請 counselor.submit(leave); } }
到此這篇關(guān)于Java設(shè)計模式之責(zé)任鏈模式詳解的文章就介紹到這了,更多相關(guān)Java責(zé)任鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實現(xiàn)猜數(shù)字小游戲(Swing版)
這篇文章主要介紹了java實現(xiàn)猜數(shù)字小游戲,Swing編程版的猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05通過Maven進(jìn)行jedis連接redis的實現(xiàn)
這篇文章主要介紹了通過Maven進(jìn)行jedis連接redis的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Java實現(xiàn)PDF轉(zhuǎn)為線性PDF詳解
線性化PDF文件是PDF文件的一種特殊格式,可以通過Internet更快地進(jìn)行查看。本文將通過后端Java程序?qū)崿F(xiàn)將PDF文件轉(zhuǎn)為線性化PDF。感興趣的可以了解一下2021-12-12mybatis中查詢結(jié)果為空時不同返回類型對應(yīng)返回值問題
這篇文章主要介紹了mybatis中查詢結(jié)果為空時不同返回類型對應(yīng)返回值問題,本文分幾種方法給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-10-10SpringBoot使用@Cacheable時設(shè)置部分緩存的過期時間方式
這篇文章主要介紹了SpringBoot使用@Cacheable時設(shè)置部分緩存的過期時間方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot中使用@Scheduled注解創(chuàng)建定時任務(wù)的實現(xiàn)
這篇文章主要介紹了SpringBoot中使用@Scheduled注解創(chuàng)建定時任務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06