責(zé)任鏈模式
在現(xiàn)實生活中,常常會出現(xiàn)這樣的事例:一個請求有多個對象可以處理,但每個對象的處理條件或權(quán)限不同。例如,公司員工請假,可批假的領(lǐng)導(dǎo)有部門負(fù)責(zé)人、副總經(jīng)理、總經(jīng)理等,但每個領(lǐng)導(dǎo)能批準(zhǔn)的天數(shù)不同,員工必須根據(jù)自己要請假的天數(shù)去找不同的領(lǐng)導(dǎo)簽名,也就是說員工必須記住每個領(lǐng)導(dǎo)的姓名、電話和地址等信息,這增加了難度。這樣的例子還有很多,如找領(lǐng)導(dǎo)出差報銷、生活中的擊鼓傳花游戲等。
定義:
又名職責(zé)鏈模式,為了避免請求發(fā)送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當(dāng)有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。 用大白話講,就是一個任務(wù),有多個處理類可以進行處理,但是多個處理類只有一個處理類可以處理它,這需要根據(jù)這個任務(wù)類的本身情況決定,因此需要將這個任務(wù)按照處理類的順序進行處理,我們只需要將這個任務(wù)丟給第一個處理類即可返回結(jié)果,因為它如果無法處理會自動轉(zhuǎn)交給下一個更強的處理類,一直找到合適的處理類為止,否則返回null。這就是責(zé)任鏈模式。
職責(zé)鏈模式主要包含以下角色:
- 抽象處理者(Handler)角色:定義一個處理請求的接口,包含抽象處理方法和一個后繼連接。
- 具體處理者(Concrete Handler)角色:實現(xiàn)抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉(zhuǎn)給它的后繼者。
- 客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關(guān)心處理細節(jié)和請求的傳遞過程。
案例實現(xiàn)
現(xiàn)需要開發(fā)一個請假流程控制系統(tǒng)。請假一天以下的假只需要小組長同意即可;請假1天到3天的假還需要部門經(jīng)理同意;請求3天到7天還需要總經(jīng)理同意才行。
類圖如下:
代碼
首先定義請假條類,包括請假人、請假天數(shù)、請假內(nèi)容:
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;
}
}
接著定義處理者類,小組長、部門經(jīng)理、總經(jīng)理都是繼承處理者類:
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, int numEnd) {
this.numStart = numStart;
this.numEnd = numEnd;
}
//設(shè)置上級領(lǐng)導(dǎo)
public void setNextHandler(Handler nextHandler){
this.nextHandler = nextHandler;
}
//各級領(lǐng)導(dǎo)處理請假條方法
protected abstract void handleLeave(LeaveRequest leave);
//提交請假條
public final void submit(LeaveRequest leave){
//如果請假天數(shù)達到該領(lǐng)導(dǎo)者的處理要求
if(leave.getNum() >= this.numStart){
if(leave.getNum()<=this.numEnd){
this.handleLeave(leave); //本級領(lǐng)導(dǎo)處理
}
//如果還有上級 并且請假天數(shù)超過了當(dāng)前領(lǐng)導(dǎo)的處理范圍
if(null != this.nextHandler && leave.getNum() > numEnd){
this.nextHandler.submit(leave);//繼續(xù)提交
} else {
System.out.println("流程結(jié)束");
}
}
}
}
下面定義小組長、部門經(jīng)理、總經(jīng)理,都是Handler的實現(xiàn)類:
// 小組長實現(xiàn)類
public class GroupLeader extends Handler {
public GroupLeader() {
//小組長處理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("小組長審批:同意。");
}
}
// 部門經(jīng)理實現(xiàn)類
public class GeneralManager extends Handler{
public GeneralManager() {
//部門經(jīng)理處理7天以上的請假
super(Handler.NUM_SEVEN+1,365);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "請假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("總經(jīng)理審批:同意。");
}
}
// 總經(jīng)理實現(xiàn)類
public class Manager extends Handler {
public Manager() {
//部門經(jīng)理處理4-7天的請假
super(Handler.NUM_THREE+1, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "請假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部門經(jīng)理審批:同意。");
}
}
客戶端測試類:
public class Main {
public static void main(String[] args) {
LeaveRequest leaveRequest = new LeaveRequest("小明", 5, "結(jié)婚");
// 各級別領(lǐng)導(dǎo)
GroupLeader groupLeader = new GroupLeader();
Manager manager = new Manager();
GeneralManager generalManager = new GeneralManager();
groupLeader.setNextHandler(manager);
manager.setNextHandler(generalManager);
// 看見沒有,優(yōu)點就是只要提交一次全部會處理掉
groupLeader.submit(leaveRequest);
}
}
輸出結(jié)果:
小明請假5天,結(jié)婚。
部門經(jīng)理審批:同意。
流程結(jié)束
優(yōu)點:
-
降低了對象之間的耦合度:該模式降低了請求發(fā)送者和接收者的耦合度。
-
增強了系統(tǒng)的可擴展性: 可以根據(jù)需要增加新的請求處理類,滿足開閉原則。
-
增強了給對象指派職責(zé)的靈活性:當(dāng)工作流程發(fā)生變化,可以動態(tài)地改變鏈內(nèi)的成員或者修改它們的次序,也可動態(tài)地新增或者刪除責(zé)任。
-
責(zé)任鏈簡化了對象之間的連接: 一個對象只需保持一個指向其后繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句。
-
責(zé)任分擔(dān):每個類只需要處理自己該處理的工作,不能處理的傳遞給下一個對象完成,明確各類的責(zé)任范圍,符合類的單一職責(zé)原則。文章來源:http://www.zghlxwxcb.cn/news/detail-792108.html
缺點:
- 不能保證每個請求一定被處理。由于一個請求沒有明確的接收者,所以不能保證它一定會被處理,該請求可能一直傳到鏈的末端都得不到處理。
- 對比較長的職責(zé)鏈,請求的處理可能涉及多個處理對象,系統(tǒng)性能將受到一定影響。
- 職責(zé)鏈建立的合理性要靠客戶端來保證,增加了客戶端的復(fù)雜性,可能會由于職責(zé)鏈的錯誤設(shè)置而導(dǎo)致系統(tǒng)出錯,如可能會造成循環(huán)調(diào)用。
參考內(nèi)容:
傳智播客設(shè)計模式相關(guān)筆記(主要)
https://zhuanlan.zhihu.com/p/94660491文章來源地址http://www.zghlxwxcb.cn/news/detail-792108.html
到了這里,關(guān)于行為型設(shè)計模式——責(zé)任鏈模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!