1. 程式人生 > >設計模式(六):責任鏈模式

設計模式(六):責任鏈模式

責任鏈設計模式是行為設計模式之一。

責任鏈模式用於在軟體設計中實現鬆散耦合,其中來自客戶端的請求被傳遞到物件鏈以處理它們。然後鏈中的物件將自己決定誰將處理請求以及是否需要將請求傳送到鏈中的下一個物件。

JDK中的責任鏈模式示例

讓我們看一下JDK中責任鏈模式的例子,然後我們將繼續實現這種模式的真例項子。我們知道在try-catch塊程式碼中我們可以有多個catch塊。這裡每個catch塊都是處理該特定異常的處理器。

因此當try塊中發生任何異常時,它會發送到第一個catch塊進行處理。如果catch塊無法處理它,它會將請求轉發到鏈中的下一個物件,即下一個catch塊。如果即使最後一個catch塊也無法處理它,那麼異常將被丟擲連結到呼叫程式。

責任鏈設計模式示例

責任鏈模式的一個很好的例子是ATM分配機器。使用者按照定義的貨幣賬單輸入要分配的金額和機器分配金額,例如50\(,20\),10$等。 如果使用者輸入的數量不是10的倍數,則會引發錯誤。我們將使用Chain of Responsibility模式來實現此解決方案。鏈將以與下圖相同的順序處理請求。 請注意,我們可以在單應用程式中輕鬆實現此解決方案,但隨後複雜性將增加,解決方案將緊密耦合。因此,我們將建立一系列分配系統,以分配50美元,20美元和10美元的賬單。

責任鏈設計模式 - 基類和介面

我們可以建立一個類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 Dispense介面如下所示。 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);
        }
    }

}

這裡要注意的重點是分配方法的實施。您會注意到每個實現都在嘗試處理請求,並且根據數量,它可能會處理部分或全部部分。 如果其中一個鏈不能完全處理它,它會將請求傳送到鏈中的下一個處理器以處理剩餘的請求。如果處理器無法處理任何內容,它只會將相同的請求轉發到下一個鏈。

責任鏈設計模式 - 建立鏈

這是非常重要的一步,我們應該仔細建立鏈,否則處理器可能根本沒有得到任何請求。例如,在我們的實現中,如果我們將第一個處理器鏈保持為Dollar10Dispenser然後Dollar20Dispenser,那麼請求將永遠不會被轉發到第二個處理器,並且鏈將變得無用。

這是我們的ATM Dispenser實現,用於處理使用者請求的數量。

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));
        }

    }

}

當我們執行上面的應用程式時,我們得到如下的輸出。

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.

責任鏈設計模式類圖

我們的ATM分配示例的責任鏈設計模式實現如下圖所示。

責任鏈設計模式重點

  • 客戶端不知道鏈的哪個部分將處理請求,它將把請求傳送到鏈中的第一個物件。例如,在我們的程式中,ATMDispenseChain不知道誰在處理分配輸入金額的請求。
  • 鏈中的每個物件都有自己的實現來處理請求,全部或部分或將其傳送到鏈中的下一個物件。
  • 鏈中的每個物件都應該引用鏈中的下一個物件來轉發請求,它由java組成。
  • 仔細建立鏈非常重要,否則可能會出現請求永遠不會轉發到特定處理器或鏈中沒有能夠處理請求的物件的情況。在我的實現中,我添加了對使用者輸入數量的檢查,以確保它被所有處理器完全處理,但是如果請求到達最後一個物件並且鏈中沒有其他物件,我們可能不檢查它並丟擲異常將請求轉發給。這是一個設計決定。
  • 責任鏈設計模式很好地實現了失去耦合,但如果大多數程式碼在所有實現中都很常見,那麼它會帶來很多實現類和維護問題的權衡。

JDK中的責任鏈模式示例

  • java.util.logging.Logger中的#日誌()
  • javax.servlet.Filter的#的doFilter() 這就是責任鏈設計模式的全部內容,我希望你喜歡它,並且能夠清楚你對這種設計模式的理解。