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


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

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

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

這就是責任鏈設計模式的全部內容,我希望你喜歡它,並且能夠清楚你對這種設計模式的理解。

翻譯:journaldev


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM