Java通俗易懂系列設(shè)計(jì)模式之責(zé)任鏈模式
概述
責(zé)任鏈設(shè)計(jì)模式是行為設(shè)計(jì)模式之一。

責(zé)任鏈模式用于在軟件設(shè)計(jì)中實(shí)現(xiàn)松散耦合,其中來自客戶端的請求被傳遞到對象鏈以處理它們。然后鏈中的對象將自己決定誰將處理請求以及是否需要將請求發(fā)送到鏈中的下一個(gè)對象。
JDK中的責(zé)任鏈模式示例
讓我們看一下JDK中責(zé)任鏈模式的例子,然后我們將繼續(xù)實(shí)現(xiàn)這種模式的真實(shí)例子。我們知道在try-catch塊代碼中我們可以有多個(gè)catch塊。這里每個(gè)catch塊都是處理該特定異常的處理器。
因此當(dāng)try塊中發(fā)生任何異常時(shí),它會發(fā)送到第一個(gè)catch塊進(jìn)行處理。如果catch塊無法處理它,它會將請求轉(zhuǎn)發(fā)到鏈中的下一個(gè)對象,即下一個(gè)catch塊。如果即使最后一個(gè)catch塊也無法處理它,那么異常將被拋出鏈接到調(diào)用程序。
責(zé)任鏈設(shè)計(jì)模式示例
責(zé)任鏈模式的一個(gè)很好的例子是ATM分配機(jī)器。用戶按照定義的貨幣賬單輸入要分配的金額和機(jī)器分配金額,例如50美元,20美元,10美元等。
如果用戶輸入的數(shù)量不是10的倍數(shù),則會引發(fā)錯(cuò)誤。我們將使用Chain of Responsibility模式來實(shí)現(xiàn)此解決方案。鏈將以與下圖相同的順序處理請求。

請注意,我們可以在單應(yīng)用程序中輕松實(shí)現(xiàn)此解決方案,但隨后復(fù)雜性將增加,解決方案將緊密耦合。因此,我們將創(chuàng)建一系列分配系統(tǒng),以分配50美元,20美元和10美元的賬單。
責(zé)任鏈設(shè)計(jì)模式 - 基類和接口
我們可以創(chuàng)建一個(gè)類Currency來存儲分配和鏈實(shí)現(xiàn)使用的數(shù)量。
Currency.java
package com.journaldev.design.chainofresponsibility;
public class Currency {
private int amount;
public Currency(int amt){
this.amount=amt;
}
public int getAmount(){
return this.amount;
}
}
基接口應(yīng)該有一個(gè)方法來定義鏈中的下一個(gè)處理器以及處理請求的方法。我們的ATM Dispense界面如下所示。
DispenseChain.java
package com.journaldev.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
責(zé)任鏈模式 - 鏈實(shí)現(xiàn)
我們需要?jiǎng)?chuàng)建不同的處理器類來實(shí)現(xiàn)DispenseChain接口并提供分配方法的實(shí)現(xiàn)。由于我們正在開發(fā)我們的系統(tǒng)以使用三種類型的貨幣賬單--50美元,20美元和10美元,我們將創(chuàng)建三個(gè)具體實(shí)施。
Dollar50Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar50Dispenser implements DispenseChain {
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 50){
int num = cur.getAmount()/50;
int remainder = cur.getAmount() % 50;
System.out.println("Dispensing "+num+" 50$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
Dollar20Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar20Dispenser implements DispenseChain{
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 20){
int num = cur.getAmount()/20;
int remainder = cur.getAmount() % 20;
System.out.println("Dispensing "+num+" 20$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
Dollar10Dispenser.java
package com.journaldev.design.chainofresponsibility;
public class Dollar10Dispenser implements DispenseChain {
private DispenseChain chain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.chain=nextChain;
}
@Override
public void dispense(Currency cur) {
if(cur.getAmount() >= 10){
int num = cur.getAmount()/10;
int remainder = cur.getAmount() % 10;
System.out.println("Dispensing "+num+" 10$ note");
if(remainder !=0) this.chain.dispense(new Currency(remainder));
}else{
this.chain.dispense(cur);
}
}
}
這里要注意的重點(diǎn)是分配方法的實(shí)施。您會注意到每個(gè)實(shí)現(xiàn)都在嘗試處理請求,并且根據(jù)數(shù)量,它可能會處理部分或全部部分。
如果其中一個(gè)鏈不能完全處理它,它會將請求發(fā)送到鏈中的下一個(gè)處理器以處理剩余的請求。如果處理器無法處理任何內(nèi)容,它只會將相同的請求轉(zhuǎn)發(fā)到下一個(gè)鏈。
責(zé)任鏈設(shè)計(jì)模式 - 創(chuàng)建鏈
這是非常重要的一步,我們應(yīng)該仔細(xì)創(chuàng)建鏈,否則處理器可能根本沒有得到任何請求。例如,在我們的實(shí)現(xiàn)中,如果我們將第一個(gè)處理器鏈保持為Dollar10Dispenser然后Dollar20Dispenser,那么請求將永遠(yuǎn)不會被轉(zhuǎn)發(fā)到第二個(gè)處理器,并且鏈將變得無用。
這是我們的ATM Dispenser實(shí)現(xiàn),用于處理用戶請求的數(shù)量。
ATMDispenseChain.java
package com.journaldev.design.chainofresponsibility;
import java.util.Scanner;
public class ATMDispenseChain {
private DispenseChain c1;
public ATMDispenseChain() {
// initialize the chain
this.c1 = new Dollar50Dispenser();
DispenseChain c2 = new Dollar20Dispenser();
DispenseChain c3 = new Dollar10Dispenser();
// set the chain of responsibility
c1.setNextChain(c2);
c2.setNextChain(c3);
}
public static void main(String[] args) {
ATMDispenseChain atmDispenser = new ATMDispenseChain();
while (true) {
int amount = 0;
System.out.println("Enter amount to dispense");
Scanner input = new Scanner(System.in);
amount = input.nextInt();
if (amount % 10 != 0) {
System.out.println("Amount should be in multiple of 10s.");
return;
}
// process the request
atmDispenser.c1.dispense(new Currency(amount));
}
}
}
當(dāng)我們運(yùn)行上面的應(yīng)用程序時(shí),我們得到如下的輸出。
Enter amount to dispense
530
Dispensing 10 50$ note
Dispensing 1 20$ note
Dispensing 1 10$ note
Enter amount to dispense
100
Dispensing 2 50$ note
Enter amount to dispense
120
Dispensing 2 50$ note
Dispensing 1 20$ note
Enter amount to dispense
15
責(zé)任鏈設(shè)計(jì)模式類圖
我們的ATM分配示例的責(zé)任鏈設(shè)計(jì)模式實(shí)現(xiàn)如下圖所示。

責(zé)任鏈設(shè)計(jì)模式重點(diǎn)
- 客戶端不知道鏈的哪個(gè)部分將處理請求,它將把請求發(fā)送到鏈中的第一個(gè)對象。例如,在我們的程序中,ATMDispenseChain不知道誰在處理分配輸入金額的請求。
- 鏈中的每個(gè)對象都有自己的實(shí)現(xiàn)來處理請求,全部或部分或?qū)⑵浒l(fā)送到鏈中的下一個(gè)對象。
- 鏈中的每個(gè)對象都應(yīng)該引用鏈中的下一個(gè)對象來轉(zhuǎn)發(fā)請求,它由java組成。
- 仔細(xì)創(chuàng)建鏈非常重要,否則可能會出現(xiàn)請求永遠(yuǎn)不會轉(zhuǎn)發(fā)到特定處理器或鏈中沒有能夠處理請求的對象的情況。在我的實(shí)現(xiàn)中,我添加了對用戶輸入數(shù)量的檢查,以確保它被所有處理器完全處理,但是如果請求到達(dá)最后一個(gè)對象并且鏈中沒有其他對象,我們可能不檢查它并拋出異常將請求轉(zhuǎn)發(fā)給。這是一個(gè)設(shè)計(jì)決定。
- 責(zé)任鏈設(shè)計(jì)模式很好地實(shí)現(xiàn)了失去耦合,但如果大多數(shù)代碼在所有實(shí)現(xiàn)中都很常見,那么它會帶來很多實(shí)現(xiàn)類和維護(hù)問題的權(quán)衡。
JDK中的責(zé)任鏈模式示例
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
以上就是Java通俗易懂系列設(shè)計(jì)模式之責(zé)任鏈模式的詳細(xì)內(nèi)容,更多關(guān)于Java設(shè)計(jì)模式的資料請關(guān)注腳本之家其它相關(guān)文章!
- Java實(shí)現(xiàn)設(shè)計(jì)模式之責(zé)任鏈模式
- Java設(shè)計(jì)模式之責(zé)任鏈模式詳解
- Java中常用的設(shè)計(jì)模式之責(zé)任鏈模式詳解
- java設(shè)計(jì)模式(實(shí)戰(zhàn))-責(zé)任鏈模式
- Java 設(shè)計(jì)模式之責(zé)任鏈模式及異步責(zé)任鏈詳解
- Java設(shè)計(jì)模式之java責(zé)任鏈模式詳解
- java設(shè)計(jì)模式責(zé)任鏈模式原理案例詳解
- 詳解Java實(shí)現(xiàn)設(shè)計(jì)模式之責(zé)任鏈模式
- Java設(shè)計(jì)模式之責(zé)任鏈模式詳解
- 一文搞懂Java設(shè)計(jì)模式之責(zé)任鏈模式
- Java設(shè)計(jì)模式之責(zé)任鏈模式
相關(guān)文章
java天數(shù)計(jì)算函數(shù)(當(dāng)前月天數(shù)、某月總天數(shù)及某月剩余天數(shù))4種方法實(shí)現(xiàn)代碼
日常開發(fā)中會遇到關(guān)于日期的計(jì)算,比如當(dāng)月的天數(shù)、兩日期之間的天數(shù)、當(dāng)月剩余天數(shù)等等,這篇文章主要給大家介紹了關(guān)于java天數(shù)計(jì)算函數(shù)(當(dāng)前月天數(shù)、某月總天數(shù)及某月剩余天數(shù))4種方法實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2023-10-10
Spring的事件機(jī)制知識點(diǎn)詳解及實(shí)例分析
在本篇內(nèi)容里小編給大家分享的是一篇關(guān)于Spring的事件機(jī)制知識點(diǎn)詳解及實(shí)例分析,有需要的朋友么可以參考下。2021-12-12
Spring Boot應(yīng)用上傳文件時(shí)報(bào)錯(cuò)的原因及解決方案
這篇文章主要介紹了Spring Boot應(yīng)用上傳文件時(shí)報(bào)錯(cuò)的原因及解決方案,幫助大家更好的理解和學(xué)習(xí)使用spring boot框架,感興趣的朋友可以了解下2021-02-02
SpringBoot服務(wù)端數(shù)據(jù)校驗(yàn)過程詳解
這篇文章主要介紹了SpringBoot服務(wù)端數(shù)據(jù)校驗(yàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
淺析Java中XPath和JsonPath以及SpEL的用法與對比
XPath,即XML路徑語言,是一種用于在XML文檔中查找信息的語言,JsonPath是從XPath中發(fā)展而來的,專門用于JSON數(shù)據(jù)格式,本文主要來講講他們的用法與區(qū)別,需要的可以參考下2023-11-11
SpringBoot打War包上傳到阿里云的LINUX服務(wù)器的操作方法
這篇文章主要介紹了SpringBoot打War包上傳到阿里云的LINUX服務(wù)器,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Mybatis如何根據(jù)List批量查詢List結(jié)果
這篇文章主要介紹了Mybatis如何根據(jù)List批量查詢List結(jié)果,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03

