链式责任模式是行为设计模式之一。
责任链设计模式
责任链模式用于在软件设计中实现松耦合,客户端的请求被传递给一系列对象进行处理。然后,链中的对象将自行决定谁将处理请求,以及是否需要将请求发送到链中的下一个对象。
JDK中的责任链模式示例
让我们看一下 JDK 中责任链模式的例子,然后我们将继续实现这个模式的一个现实生活例子。我们知道在 try-catch 块 代码中可以有多个 catch 块。这里每个 catch 块都是一种处理特定异常的处理器。所以当在 try 块中发生任何异常时,它会被发送到第一个 catch 块进行处理。如果 catch 块无法处理它,它会将请求转发给链中的下一个对象,即下一个 catch 块。如果即使最后一个 catch 块也无法处理它,异常将被抛出到调用程序之外。
责任链设计模式示例
责任链模式的一个很好的例子是ATM取款机。用户输入要取款的金额,机器以定义的货币面额如50美元、20美元、10美元等来发放金额。如果用户输入的金额不是10的倍数,它会报错。我们将使用责任链模式来实现这个解决方案。链将按照下图所示的顺序处理请求。请注意,我们可以在一个单独的程序中轻松实现这个解决方案,但是复杂度会增加,解决方案会变得紧密耦合。因此,我们将创建一系列的发放系统,用于发放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发放接口将如下所示。DispenseChain.java
package com.journaldev.design.chainofresponsibility;
public interface DispenseChain {
void setNextChain(DispenseChain nextChain);
void dispense(Currency cur);
}
责任链模式 – 链的实现
我们需要创建不同的处理器类,它们将实现DispenseChain
接口,并提供dispense方法的实现。由于我们正在开发的系统要处理三种类型的货币钞票 – 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);
}
}
}
这里需要注意的重要一点是dispense方法的实现。您会注意到每个实现都试图处理请求,并根据金额可能处理部分或全部请求。如果链中的某个处理器无法完全处理请求,它会将请求发送到链中的下一个处理器以处理剩余请求。如果处理器无法处理任何内容,它将简单地将相同的请求转发到下一个链。
责任链设计模式 – 创建链
这是一个非常重要的步骤,我们应该仔细创建这个链,否则处理器可能根本不会收到任何请求。例如,在我们的实现中,如果我们将第一个处理器链保持为Dollar10Dispenser
,然后是Dollar20Dispenser
,那么请求将永远不会转发到第二个处理器,链将变得无效。以下是我们的ATM发钞机实现,用于处理用户请求的金额。ATMDispenseChain.java
package com.journaldev.design.chainofresponsibility;
import java.util.Scanner;
public class ATMDispenseChain {
private DispenseChain c1;
public ATMDispenseChain() {
// 初始化链
this.c1 = new Dollar50Dispenser();
DispenseChain c2 = new Dollar20Dispenser();
DispenseChain c3 = new Dollar10Dispenser();
// 设置责任链
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;
}
// 处理请求
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.
责任链设计模式类图
责任链设计模式重要要点
- 客户不知道链的哪个部分将处理请求,并且它将请求发送到链中的第一个对象。例如,在我们的程序中,ATMDispenseChain 不知道谁在处理请求以分发输入的金额。
- 链中的每个对象都将有自己的实现来处理请求,无论是完全的还是部分的,或者将其发送到链中的下一个对象。
- 链中的每个对象都应该有对链中下一个对象的引用以转发请求,这是通过 java 组合 实现的。
- 仔细创建链非常重要,否则可能出现这样一种情况,即请求永远不会被转发到特定的处理器,或者链中没有能够处理请求的对象。在我的实现中,我已经添加了对用户输入金额的检查,以确保所有处理器都能完全处理,但如果请求到达最后一个对象并且没有更多的对象在链中将请求转发给它,则可能不会检查它并抛出异常。这是一个设计决策。
- 责任链设计模式是实现松耦合的好方法,但如果大部分代码在所有实现中都是通用的,则会带来大量的实现类和维护问题。
JDK 中责任链模式的示例
- java.util.logging.Logger#log()
- javax.servlet.Filter#doFilter()
这就是责任链设计模式的全部内容,希望你喜欢并且能够清楚地理解这个设计模式。
Source:
https://www.digitalocean.com/community/tutorials/chain-of-responsibility-design-pattern-in-java