通俗易懂系列 | 設計模式(六):責任鏈模式

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

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

JDK中的責任鏈模式示例

讓咱們看一下JDK中責任鏈模式的例子,而後咱們將繼續實現這種模式的真實例子。咱們知道在try-catch塊代碼中咱們能夠有多個catch塊。這裏每一個catch塊都是處理該特定異常的處理器。ide

所以當try塊中發生任何異常時,它會發送到第一個catch塊進行處理。若是catch塊沒法處理它,它會將請求轉發到鏈中的下一個對象,即下一個catch塊。若是即便最後一個catch塊也沒法處理它,那麼異常將被拋出連接到調用程序。this

責任鏈設計模式示例

責任鏈模式的一個很好的例子是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.javacode

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.javablog

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#log()
  • javax.servlet.Filter#doFilter()

這就是責任鏈設計模式的所有內容,我但願你喜歡它,而且可以清楚你對這種設計模式的理解。

翻譯:journaldev

相關文章
相關標籤/搜索