责任链是用来实现解耦合的软件设计,来自客户端的请求被传递到链条的对象来处理他们,然后在该链中的对象将自己决定谁将处理请求和是否需要请求发送给链中的下一个处理对象或没有下一个对象。
让我们来看看责任链模式中的JDK的例子,然后我们将着手实现这一模式的例子。我们知道,我们可以在一个try-catch块代码中的多个catch块。在这里,每个catch块都是一个处理器来处理特定的异常。所以,当任何异常在try块中发生,它发送给第一个catch块来处理。如果在catch块不能处理它,它在转发链,即下一个catch块的请求下一个对象。如果连最后的catch块不能处理它,那么这个异常将会抛出到链的调用程序之外。
一个责任链模式的一个很好的例子是ATM机处理。用户输入将被分配总计数 ,机器根据货币票额信息分类,例如$ 50,$ 20,$ 10等。如果用户输入的量不是10的倍数,则会引发错误。我们将使用责任链模式来实现这个解决方案。链将处理在相同的顺序如下图。
需要注意的是,我们可以在一个程序中很容易地实现这种解决方案,但随后的复杂性将增加,程序被紧密地耦合。因此,我们将创建一个链式系统来分发处理,以$
50,$ 20和$ 10为单位进行处理。
基类与接口设计:
我们创建Currency 类,用于存储总计数,供链式分发处理参考
package com.journaldev.design.chainofresponsibility; public class Currency { private int amount; public Currency(int amt){ this.amount=amt; } public int getAmount(){ return this.amount; } }
基类接口实现应该有一个定义在链中的下一个处理器,并且将处理该请求的方法的方法。我们的自动取款机分发接口会像下面一样
package com.journaldev.design.chainofresponsibility; public interface DispenseChain { void setNextChain(DispenseChain nextChain); void dispense(Currency cur); }
具体链式实现:
我们需要创建不同的实现类来分别实现DispenseChain接口,并且实现对应分发方法,由于我们开发的系统处理的是三种货币单位,因此我们需要三个实现类
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);
}
}
}
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); } } }
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提款机执行处理用户请求的金额
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.
类之间关系图:
知识要点总结:
1,客户端不知道该链中的一部分将是对请求的处理,它会请求发送到所述第一对象中的链。例如,在我们的程序
ATMDispenseChain不知道谁正在处理以分配所输入的量的要求。
2,链中的每个对象都有它自己的实现来处理请求,无论是全部或部分,或将其链传送到下一个对象。
3,在链中的每个对象应具有参考在链中的下一对象转发到,其由java的组合物取得的请求。
4,谨慎小心处理链是非常重要的,否则有可能是请求将不会被转发到一个特定的处理器或者有链中没有对象谁能够处理请求的情况。
在我的实现,我已经加入了检查用户输入的金额,以确保它得到了所有的处理器完全处理,但我们可能不会检查它并抛出异常,
如果该请求到达的最后一个对象,并有链没有其它目的转发请求。这是一个设计决策。
5,责任链模式是很好的实现失去联结,但它自带的权衡有很多的实现类和维修问题,如果大部分的代码在所有实现共同的。
原文链接:http://www.journaldev.com/1617/chain-of-responsibility-design-pattern-in-java