Java中的责任链设计模式

时间:2020-02-23 14:36:10  来源:igfitidea点击:

责任链设计模式是行为设计模式之一。

责任链设计模式

责任链模式用于实现软件设计中的松散耦合,其中将来自客户端的请求传递给对象链以对其进行处理。
然后,链中的对象将自行决定将由谁来处理请求,以及是否需要将请求发送到链中的下一个对象。

JDK中的责任链模式示例

让我们看一下JDK中的责任链模式示例,然后我们将继续实施这种模式的真实示例。
我们知道在try-catch块代码中可以有多个catch块。
其中每个catch块都是一种处理器,用于处理该特定异常。

因此,当try块中发生任何异常时,它将发送到第一个catch块进行处理。
如果catch块无法处理它,则将请求转发到链中的下一个对象,即下一个catch块。
如果即使最后一个catch块也无法处理它,则将异常抛出到调用程序的链外。

责任链设计模式示例

责任链模式的一个很好的例子是ATM分配机。
用户输入要分配的金额,并根据已定义的货币票据(例如50 $,20 $,10 $等)输入机器分配的金额。

如果用户输入的金额不是10的倍数,则会引发错误。
我们将使用责任链模式来实现此解决方案。
链将按照下图所示的顺序处理请求。

请注意,我们可以在单个程序本身中轻松实现此解决方案,但是复杂性将增加,并且解决方案将紧密耦合。
因此,我们将创建一个分配系统链,以分配50美元,20美元和10美元的钞票。

责任链设计模式–基类和接口

我们可以创建一个"货币"类,该类将存储要分配的数量并由链实现使用。

Currency.java

package com.theitroad.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.theitroad.design.chainofresponsibility;

public interface DispenseChain {

	void setNextChain(DispenseChain nextChain);
	
	void dispense(Currency cur);
}

责任链模式–链实施

我们需要创建不同的处理器类来实现DispenseChain接口并提供Dispense方法的实现。
由于我们正在开发可使用三种类型的货币法案(50美元,20美元和10美元)的系统,因此我们将创建三种具体的实现。

Dollar50Dispenser.java

package com.theitroad.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.theitroad.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.theitroad.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自动提款机实施方案,用于处理用户请求的金额。

ATMDispenseChain.java

package com.theitroad.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()