Java職責鏈模式的深入了解
一、職責鏈模式的定義與特點
定義:
為了避免請求發(fā)送者與多個請求處理者耦合在一起,于是將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。
比如我們的審批制度,低等級的審批不了的,交給上一級審批,依次類推,直到審批結束。
在責任鏈模式中,客戶只需要將請求發(fā)送到責任鏈上即可,無須關心請求的處理細節(jié)和請求的傳遞過程,請求會自動進行傳遞。所以責任鏈將請求的發(fā)送者和請求的處理者解耦了。
特點:
1. 降低了對象之間的耦合度。該模式使得一個對象無須知道到底是哪一個對象處理其請求以及鏈的結構,發(fā)送者和接收者也無須擁有對方的明確信息。
2. 增強了系統的可擴展性。可以根據需要增加新的請求處理類,滿足開閉原則。
3. 增強了給對象指派職責的靈活性。當工作流程發(fā)生變化,可以動態(tài)地改變鏈內的成員或者調動它們的次序,也可動態(tài)地新增或者刪除責任。
4. 責任鏈簡化了對象之間的連接。每個對象只需保持一個指向其后繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句。
5. 責任分擔。每個類只需要處理自己該處理的工作,不該處理的傳遞給下一個對象完成,明確各類的責任范圍,符合類的單一職責原則。
缺點:
1. 不能保證每個請求一定被處理。由于一個請求沒有明確的接收者,所以不能保證它一定會被處理,該請求可能一直傳到鏈的末端都得不到處理。
2. 對比較長的職責鏈,請求的處理可能涉及多個處理對象,系統性能將受到一定影響。 3. 職責鏈建立的合理性要靠客戶端來保證,增加了客戶端的復雜性,可能會由于職責鏈的錯誤設置而導致系統出錯,如可能會造成循環(huán)調用。
二、職責鏈模式的結構
職責鏈模式的主要角色
抽象處理者(Handler)角色:定義一個處理請求的接口,包含抽象處理方法和一個后繼連接。
具體處理者(Concrete Handler)角色:實現抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉給它的后繼者。
客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關心處理細節(jié)和請求的傳遞過程。
責任鏈模式的本質是解耦請求與處理,讓請求在處理鏈中能進行傳遞與被處理;理解責任鏈模式應當理解其模式,而不是其具體實現。責任鏈模式的獨到之處是將其節(jié)點處理者組合成了鏈式結構,并允許節(jié)點自身決定是否進行請求處理或轉發(fā),相當于讓請求流動起來。

三、職責鏈模式案例
案例需求:編寫程序完成學習采購項目審批系統
采購員采購教學器材,如果金額小于5000,由教學主任審批,
如果金額小于10000,由院長審批
如果金額小于30000,又副校長審批
如果金額大于30000,由校長審批
采用職責鏈模式
那么該案例我們傳統的方法大致就是采用分支語句去解決,但是這個會導致我們又違反開閉原則,就是如果我們修改審批人的話會去修改類中內容,所以我們采取職責鏈模式,將審批人類和處理類分開,解耦,分別去實現他。這樣的話我們想要加審批人只需要添加新類即可
UML類圖

請求審批類
package com.chainOfResponsibilityPattern.SubmitAccount;
/**
* @author wang
* @version 1.0
* @packageName com.chainOfResponsibilityPattern.SubmitAccount
* @className PurchaseRequest
* @date 2021/12/28 19:31
* @Descriptio 該類為請求對象,封裝了請求處理的相關信息
* 變量分別為請求類型,編號,價格
*/
public class PurchaseRequest {
private String type;
private int id;
private float price;
public PurchaseRequest(String type, int id, float price) {
this.type = type;
this.id = id;
this.price = price;
}
public String getType() {
return type;
}
public int getId() {
return id;
}
public float getPrice() {
return price;
}
}抽象處理類:
package com.chainOfResponsibilityPattern.SubmitAccount;
/**
* @author wang
* @version 1.0
* @packageName com.chainOfResponsibilityPattern.SubmitAccount
* @className ApprovePeople
* @date 2021/12/28 19:36
* @Description 處理審批人的類,抽象處理請求的類
*/
public abstract class ApprovePeople {
/**
* 下一個審批人
*/
ApprovePeople approvePeople;
/**
* 審批人名稱
*/
String name;
public ApprovePeople(String name) {
this.name = name;
}
/**
* @param approvePeople
* @Date 2021/12/28 19:39
* @Param
* @Return void
* @MetodName setNext
* @Author wang
* @Description 設置下一個審批人的對象
*/
public void setNext(ApprovePeople approvePeople) {
this.approvePeople = approvePeople;
}
/**
* @param purchaseRequest
* @Date 2021/12/28 19:40
* @Param
* @Return void
* @MetodName handleRequest
* @Author wang
* @Description 處理請求的方法,由該類的子類根據自己的情況去實現
*/
public abstract void handleRequest(PurchaseRequest purchaseRequest);
}教學主任類:
package com.chainOfResponsibilityPattern.SubmitAccount;
/**
* @author wang
* @version 1.0
* @packageName com.chainOfResponsibilityPattern.SubmitAccount
* @className TeacherDirector
* @date 2021/12/28 19:47
* @Description 教學主任類,具體的處理請求的類
*/
public class TeacherDirector extends ApprovePeople {
public TeacherDirector(String name) {
super(name);
}
@Override
public void handleRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() <= 5000) {
System.out.println("請求編號為:" + purchaseRequest.getId() + "\n請求類型為:" + purchaseRequest.getType() +
"\n請求金額為:" + purchaseRequest.getPrice() + "的項目被" + this.name + "處理成功");
} else {
approvePeople.handleRequest(purchaseRequest);
}
}
}院長類
package com.chainOfResponsibilityPattern.SubmitAccount;/** * @author wang * @version 1.0 * @packageName com.chainOfResponsibilityPattern.SubmitAccount * @className DeanApprove * @date 2021/12/28 19:52 * @Description 院長處理類,具體的處理請求的類 */public class DeanApprove extends ApprovePeople{ public DeanApprove(String name) { super(name); } @Override public void handleRequest(PurchaseRequest purchaseRequest) { if(purchaseRequest.getPrice()> 5000 && purchaseRequest.getPrice() <= 10000) { System.out.println("請求編號為:" + purchaseRequest.getId() + "\n請求類型為:" + purchaseRequest.getType() + "\n請求金額為:" + purchaseRequest.getPrice() + "的項目被" +this.name +"處理成功"); }else { approvePeople.handleRequest(purchaseRequest); } }}校長和副校長類類似與上,只需改動處理條件即可
客戶端測試類;
package com.chainOfResponsibilityPattern.SubmitAccount;
/**
* @author wang
* @version 1.0
* @packageName com.chainOfResponsibilityPattern.SubmitAccount
* @className ClientTest
* @date 2021/12/28 19:58
* @Description 客戶測試類
*/
public class ClientTest {
public static void main(String[] args) {
//創(chuàng)建一個請求
PurchaseRequest purchaseRequest = new PurchaseRequest("體育用品", 1, 4000);
//創(chuàng)建相關審批人
TeacherDirector zhang1 = new TeacherDirector("張主任");
DeanApprove li2 = new DeanApprove("李院長");
VicePresident chen3 = new VicePresident("陳副院長");
President liu4 = new President("劉校長");
/**
* 切記一定要讓個處理者之間連接起來,否則會報出空指針異常,且需要構成一個環(huán)
*
*/
zhang1.setNext(li2);
li2.setNext(chen3);
chen3.setNext(liu4);
liu4.setNext(zhang1);
//處理請求
zhang1.handleRequest(purchaseRequest);
}
}輸出結果
請求編號為:1
請求類型為:體育用品
請求金額為:4000.0的項目被張主任處理成功
請求編號為:2
請求類型為:修仙用品
請求金額為:300000.0的項目被劉校長處理成功
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!v
相關文章
Java高級用法中的JNA類型映射注意細節(jié)及使用問題
本文介紹了在使用JNA方法映射中應該注意的一些細節(jié)和具體的使用問題,對java??JNA類型映射注意細節(jié)感興趣的朋友一起看看吧2022-04-04
Spring?Boot?中的?@HystrixCommand?注解原理及使用方法
通過使用 @HystrixCommand 注解,我們可以輕松地實現對方法的隔離和監(jiān)控,從而提高系統的可靠性和穩(wěn)定性,本文介紹了Spring Boot 中的@HystrixCommand注解是什么,其原理以及如何使用,感興趣的朋友跟隨小編一起看看吧2023-07-07
Eclipse 2020-06 漢化包安裝步驟詳解(附漢化包+安裝教程)
這篇文章主要介紹了Eclipse 2020-06 漢化包安裝步驟(附漢化包+安裝教程),本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08

