责任链设计模式是行为设计模式 的一种。
责任链设计模式
责任链模式用于在软件设计中实现松耦合,其中来自客户端的请求被传递到对象链来处理它们。然后,链中的对象将自己决定谁将处理该请求,以及是否需要将该请求发送到链中的下一个对象。
JDK中的责任链模式示例
让我们看看JDK中的责任链模式的示例,然后我们将继续实现该模式的一个真实示例。我们知道在Try-Catch block代码中可以有多个Catch块。在这里,每个CATCH块都是一种处理特定异常的处理器。因此,当try块中发生任何异常时,它的Send将被发送到第一个Catch块进行处理。如果CATCH块无法处理它,它会将请求转发到链中的下一个对象,即下一个CATCH块。如果即使是最后一个Catch块也无法处理它,则会将异常抛出到调用程序的链外。
责任链设计模式示例
责任链模式的一个很好的例子是自动取款机 。用户输入要分配的金额,机器分配金额以定义的货币纸币表示,如50美元、20美元、10美元等。如果用户输入的金额不是10的倍数,则会抛出错误。我们将使用责任链模式来实施这一解决方案。该链将以与下图相同的顺序处理请求。请注意,我们可以在单个程序本身中轻松实现此解决方案,但这样会增加复杂性,解决方案将紧密耦合。因此,我们将创建一系列分配系统来分配50美元、20美元和10美元的账单。
责任链设计模式--基类和接口
我们可以创建一个类Currency
,它将存储链实现要分配和使用的金额。Currency.java
1package com.journaldev.design.chainofresponsibility;
2
3public class Currency {
4
5 private int amount;
6
7 public Currency(int amt){
8 this.amount=amt;
9 }
10
11 public int getAmount(){
12 return this.amount;
13 }
14}
基接口应该有一个方法来定义链中的下一个处理器和将处理请求的方法。我们的自动取款机分配界面如下所示。DispenseChain.java
1package com.journaldev.design.chainofresponsibility;
2
3public interface DispenseChain {
4
5 void setNextChain(DispenseChain nextChain);
6
7 void dispense(Currency cur);
8}
责任链模式-链实现
我们需要创建不同的处理器类来实现DispenseChain
接口并提供Dispense方法的实现。由于我们正在开发我们的系统以处理三种类型的纸币--50美元、20美元和10美元,因此我们将创建三个具体的实现。美元50Dispenser.java
1package com.journaldev.design.chainofresponsibility;
2
3public class Dollar50Dispenser implements DispenseChain {
4
5 private DispenseChain chain;
6
7 @Override
8 public void setNextChain(DispenseChain nextChain) {
9 this.chain=nextChain;
10 }
11
12 @Override
13 public void dispense(Currency cur) {
14 if(cur.getAmount() >= 50){
15 int num = cur.getAmount()/50;
16 int remainder = cur.getAmount() % 50;
17 System.out.println("Dispensing "+num+" 50$ note");
18 if(remainder !=0) this.chain.dispense(new Currency(remainder));
19 }else{
20 this.chain.dispense(cur);
21 }
22 }
23
24}
‘Dollar20Dispenser.java`
1package com.journaldev.design.chainofresponsibility;
2
3public class Dollar20Dispenser implements DispenseChain{
4
5 private DispenseChain chain;
6
7 @Override
8 public void setNextChain(DispenseChain nextChain) {
9 this.chain=nextChain;
10 }
11
12 @Override
13 public void dispense(Currency cur) {
14 if(cur.getAmount() >= 20){
15 int num = cur.getAmount()/20;
16 int remainder = cur.getAmount() % 20;
17 System.out.println("Dispensing "+num+" 20$ note");
18 if(remainder !=0) this.chain.dispense(new Currency(remainder));
19 }else{
20 this.chain.dispense(cur);
21 }
22 }
23
24}
‘Dollar10Dispenser.java`
1package com.journaldev.design.chainofresponsibility;
2
3public class Dollar10Dispenser implements DispenseChain {
4
5 private DispenseChain chain;
6
7 @Override
8 public void setNextChain(DispenseChain nextChain) {
9 this.chain=nextChain;
10 }
11
12 @Override
13 public void dispense(Currency cur) {
14 if(cur.getAmount() >= 10){
15 int num = cur.getAmount()/10;
16 int remainder = cur.getAmount() % 10;
17 System.out.println("Dispensing "+num+" 10$ note");
18 if(remainder !=0) this.chain.dispense(new Currency(remainder));
19 }else{
20 this.chain.dispense(cur);
21 }
22 }
23
24}
这里要注意的重要一点是分配方法的实现。你会注意到每个实现都在尝试处理请求,根据数量,它可能会处理部分或全部请求。如果其中一个链不能完全处理它,它会将请求发送到链中的下一个处理器来处理剩余的请求。如果处理器不能处理任何东西,它只是将相同的请求转发到下一个链。
责任链设计模式--创建链
这是一个非常重要的步骤,我们应该小心地创建链,否则处理器可能根本不会收到任何请求。例如,在我们的实现中,如果我们将第一个处理器链保持为Dollar10Dispenser
,然后保持为Dollar20Dispenser
,那么请求将永远不会被转发到第二个处理器,并且链将变得无用。下面是我们的ATM分配器实现,用于处理用户请求的金额。ATMDispenseChain.java
1package com.journaldev.design.chainofresponsibility;
2
3import java.util.Scanner;
4
5public class ATMDispenseChain {
6
7 private DispenseChain c1;
8
9 public ATMDispenseChain() {
10 // initialize the chain
11 this.c1 = new Dollar50Dispenser();
12 DispenseChain c2 = new Dollar20Dispenser();
13 DispenseChain c3 = new Dollar10Dispenser();
14
15 // set the chain of responsibility
16 c1.setNextChain(c2);
17 c2.setNextChain(c3);
18 }
19
20 public static void main(String[] args) {
21 ATMDispenseChain atmDispenser = new ATMDispenseChain();
22 while (true) {
23 int amount = 0;
24 System.out.println("Enter amount to dispense");
25 Scanner input = new Scanner(System.in);
26 amount = input.nextInt();
27 if (amount % 10 != 0) {
28 System.out.println("Amount should be in multiple of 10s.");
29 return;
30 }
31 // process the request
32 atmDispenser.c1.dispense(new Currency(amount));
33 }
34
35 }
36
37}
当我们运行上面的应用程序时,我们得到如下所示的输出。
1Enter amount to dispense
2530
3Dispensing 10 50$ note
4Dispensing 1 20$ note
5Dispensing 1 10$ note
6Enter amount to dispense
7100
8Dispensing 2 50$ note
9Enter amount to dispense
10120
11Dispensing 2 50$ note
12Dispensing 1 20$ note
13Enter amount to dispense
1415
15Amount should be in multiple of 10s.
责任链设计模式类图
责任链设计模式要点
- 客户端不知道链的哪一部分将处理请求,它会将请求发送到链中的第一个对象。例如,在我们的程序中,ATMDispenseChain不知道是谁在处理分配输入金额的请求。
- 链中的每个对象都有自己的实现来处理请求,无论是完整的还是部分的,或者将其发送到链中的下一个对象。
- 链中的每个对象都应该有对链中下一个要转发请求的对象的引用,它通过Java composition。
- 仔细创建链是非常重要的,否则可能会出现请求永远不会转发到特定处理器的情况,或者链中没有能够处理该请求的对象。在我的实现中,我为用户输入的数量添加了检查,以确保它得到所有处理器的完全处理,但如果请求到达最后一个对象,并且链中没有其他对象可以将请求转发到,我们可能不会检查它并引发异常。这是一个设计决定。
- 责任链设计模式很好地实现了松散耦合,但如果大多数代码在所有实现中都是通用的,那么它会带来大量实现类和维护问题的权衡。
JDK中的责任链模式示例
- java.util.logging.Logger# log()
- javax.servlet.Filter# doFilter()
这就是责任链设计模式,希望你喜欢它,并能澄清你对这个设计模式的理解。