Java中的责任链设计模式
责任链设计模式是行为设计模式之一。
责任链设计模式
责任链模式用于在软件设计中实现松耦合,其中客户端的请求被传递给一系列对象来处理。然后链中的对象将自行决定由谁来处理请求,以及是否需要将请求发送到链中的下一个对象。
责任链模式在JDK中的示例
让我们来看一下JDK中责任链模式的例子,然后我们将继续实现这个模式的一个现实生活例子。我们知道在try-catch代码块中可以有多个catch块。这里每个catch块都是对特定异常进行处理的处理器。因此,当try块中发生任何异常时,它被发送到第一个catch块进行处理。如果catch块无法处理它,它将将请求转发给链中的下一个对象,即下一个catch块。如果即使最后一个catch块也无法处理它,则异常被抛出到调用程序之外的链。
职责链设计模式示例
责任链模式的一个很好的例子是ATM取款机。用户输入要取出的金额,机器按照定义的货币面额(如50美元,20美元,10美元等)来取款。如果用户输入的金额不是10的倍数,就会抛出错误。我们将使用责任链模式来实现这个解决方案。链条将按照下面图片中的顺序处理请求。注意,我们可以在一个单独的程序中轻松实现这个解决方案,但是这样会增加复杂性,并且解决方案会紧密耦合。所以我们将创建一个取款系统的链条,用来取款50美元、20美元和10美元的钞票。
责任链设计模式 – 基类和接口
我们可以创建一个名为Currency的类,用于存储要发放和链式实现中使用的金额。Currency.java。
package com.Olivia.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.Olivia.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
责任链模式 – 链实现
我们需要创建不同的处理器类来实现DispenseChain接口,并提供dispense方法的实现。由于我们正在开发的系统需要与三种货币纸币 – 50美元,20美元和10美元 – 进行交互,我们将创建三个具体的实现。Dollar50Dispenser.java
package com.Olivia.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);
}
}
}
美元20元发放机.java
package com.Olivia.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);
}
}
}
十美元取款机.java
package com.Olivia.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,那么请求将永远不会转发到第二个处理器,整个链条将变得毫无用处。这是我们处理用户请求金额的自动提款机实现,ATMDispenseChain.java。
package com.Olivia.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.
职责链设计模式类图
我们自动取款机链式责任设计模式实现的示例如下图所示。
责任链设计模式的重要要点
- Client doesn’t know which part of the chain will be processing the request and it will send the request to the first object in the chain. For example, in our program ATMDispenseChain is unaware of who is processing the request to dispense the entered amount.
- Each object in the chain will have it’s own implementation to process the request, either full or partial or to send it to the next object in the chain.
- Every object in the chain should have reference to the next object in chain to forward the request to, its achieved by java composition.
- Creating the chain carefully is very important otherwise there might be a case that the request will never be forwarded to a particular processor or there are no objects in the chain who are able to handle the request. In my implementation, I have added the check for the user entered amount to make sure it gets processed fully by all the processors but we might not check it and throw exception if the request reaches the last object and there are no further objects in the chain to forward the request to. This is a design decision.
- Chain of Responsibility design pattern is good to achieve lose coupling but it comes with the trade-off of having a lot of implementation classes and maintenance problems if most of the code is common in all the implementations.
在JDK中,责任链模式的例子
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
这就是责任链设计模式的全部,希望你喜欢并且它能够帮助你清楚地理解这个设计模式。