责任链设计模式是行为设计模式之一。
责任链设计模式
责任链模式用于在软件设计中实现松散耦合,其中来自客户端的请求被传递给一系列对象来处理。然后,链中的对象将自行决定谁将处理请求,以及是否需要将请求发送到链中的下一个对象。
JDK中的责任链模式示例
讓我們查看在JDK中職責鏈模式的例子,然後我們將繼續實現這種模式的現實示例。我們知道在try-catch區塊代碼中可以有多個catch區塊。這裡的每個catch區塊都是一種處理特定異常的處理器。因此,當在try區塊中發生任何異常時,它會被發送到第一個catch區塊進行處理。如果catch區塊無法處理它,它會將請求轉發給鏈中的下一個對象,即下一個catch區塊。如果即使最後一個catch區塊也無法處理它,則將異常拋出到調用程序之外。
職責鏈設計模式示例
Chain of Responsibility 模式的一個很好的例子是 ATM 提款機。 用戶輸入要提款的金額,機器會按照指定的貨幣面額提供金額,例如 50 美元、20 美元、10 美元等。 如果用戶輸入的金額不是 10 的倍數,則會拋出錯誤。 我們將使用 Chain of Responsibility 模式來實現這個解決方案。 鏈將按照下圖的相同順序處理請求。 請注意,我們可以在一個單獨的程序中輕鬆實現此解決方案,但是這將增加複雜性並且將解決方案緊密耦合。 因此,我們將創建一個提款系統的鏈來提供 50 美元、20 美元和 10 美元的鈔票。
Chain of Responsibility 設計模式 – 基礎類和接口
我們可以創建一個類 Currency
來存儲要提供的金額,並由鏈實現使用。 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;
}
}
基本接口應該有一個方法來定義鏈中的下一個處理器和處理請求的方法。 我們的 ATM 提款接口將如下所示。 DispenseChain.java
package com.journaldev.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
責任鏈模式 – 鏈實現
我們需要創建不同的處理器類別,這些類別將實現DispenseChain
接口並提供分發方法的實現。由於我們正在開發的系統要處理三種類型的貨幣票據 – 50美元、20美元和10美元,我們將創建三個具體的實現。 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);
}
}
}
這裡需要注意的重點是dispense方法的實現。您會注意到每個實現都試圖處理請求,並根據金額可能處理部分或全部。如果其中一個鏈無法完全處理它,它會將請求發送到鏈中的下一個處理器以處理剩餘的請求。如果處理器無法處理任何事情,它只會將相同的請求轉發到下一個鏈。
責任鏈設計模式 – 創建鏈
這是一個非常重要的步驟,我們應該仔細創建這個鏈條,否則處理器可能根本不會收到任何請求。例如,在我們的實現中,如果我們將第一個處理器鏈條設置為Dollar10Dispenser
,然後是Dollar20Dispenser
,那麼請求將永遠不會轉發到第二個處理器,整個鏈條就變得無用了。這是我們的ATM發放機實現來處理用戶請求的方式。ATMDispenseChain.java
package com.journaldev.design.chainofresponsibility;
import java.util.Scanner;
public class ATMDispenseChain {
private DispenseChain c1;
public ATMDispenseChain() {
// 初始化鏈條
this.c1 = new Dollar50Dispenser();
DispenseChain c2 = new Dollar20Dispenser();
DispenseChain c3 = new Dollar10Dispenser();
// 設置責任鏈
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;
}
// 處理請求
atmDispenser.c1.dispense(new Currency(amount));
}
}
}
當我們運行上面的應用程序時,我們獲得如下輸出。
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
Amount should be in multiple of 10s.
職責鏈設計模式類圖
職責鏈設計模式的重點
- 客戶不知道鏈中的哪個部分將處理請求,它將請求發送到鏈中的第一個對象。例如,在我們的程式中,ATMDispenseChain 不知道誰正在處理請求以發送輸入金額。
- 鏈中的每個對象將有自己的實現來處理請求,可能是完全的、部分的,或者將其發送到鏈中的下一個對象。
- 鏈中的每個對象都應該有對鏈中下一個對象的引用,以轉發請求,這是通過Java組合實現的。
- 仔細創建鏈非常重要,否則可能會出現這樣的情況,即請求永遠不會被轉發到特定的處理器,或者鏈中沒有能夠處理請求的對象。在我的實現中,我已經添加了對用戶輸入金額的檢查,以確保它被所有處理器完全處理,但如果請求到達最後一個對象且鏈中沒有更多對象可以轉發請求,我們可能不檢查它並且拋出異常。這是一個設計決策。
- 職責鏈設計模式很好地實現了鬆耦合,但如果大多數代碼在所有實現中都是共同的,則存在許多實現類和維護問題。
在JDK中的责任链模式示例
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
這就是责任链设计模式的全部内容,希望您喜欢它,并且能够清楚地理解这个设计模式。
Source:
https://www.digitalocean.com/community/tutorials/chain-of-responsibility-design-pattern-in-java