GoF原文
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
一个来自客户端的请求被传递给一个对象链来处理它们。然后,链中的对象将自己决定谁将处理请求,以及是否需要将请求发送给链中的下一个对象。
责任链主要用于处理职责相同,程度不同的类
责任链模式的应用场景
在日常生活中,责任链模式是比较常见的。我们平时处理工作中的一些事务,往往是各部门协同合作来完成某一个任务的。而每个部门都有各自的职责,因此,很多时候事情完成一半,便会转交到下一个部门,直到所有部门都审批通过,事情才能完成。还有我们平时说的“过五关,斩六将”其实就是闯关,也是责任链模式的一种应用场景。责任链模式主要解耦了请求与处理,客户只需将请求发送到链上即可,不需要关心请求的具体内容和处理细节,请求会自动进行传递,直至有节点对象进行处理。
责任链模式主要适用于以下应用场景。
(1)多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
(2)在不明确指定接收者的情况下,向多个对象中的一个提交请求。
(3)可动态指定一组对象处理请求。
Bean
public class Currency {
private final int amount;
public Currency(int amt) {
amount = amt;
}
public int getAmount() {
return amount;
}
}
抽象处理者(Handler):
The base interface should have a method to define the next processor in the chain and the method that will process the request.
基本接口应该具有定义链中的下一个处理器的方法和自身处理请求的方法
public interface IDispenseChain {
//给自己指定一个背锅的
void setNextChain(IDispenseChain nextChain);
//自己处理
void dispense(Currency cur);
}
具体处理者(ConcreteHandler):
对请求进行处理,如果不感兴趣,则进行转发。
public class Dollar50Dispenser implements IDispenseChain {
private IDispenseChain chain;
@Override
public void setNextChain(IDispenseChain 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) {
chain.dispense(new Currency(remainder));
}
} else {
chain.dispense(cur);
}
}
}
public class Dollar20Dispenser implements IDispenseChain {
private IDispenseChain chain;
@Override
public void setNextChain(IDispenseChain 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) {
chain.dispense(new Currency(remainder));
}
} else {
chain.dispense(cur);
}
}
}
public class Dollar10Dispenser implements IDispenseChain {
private IDispenseChain chain;
@Override
public void setNextChain(IDispenseChain 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) {
chain.dispense(new Currency(remainder));
}
} else {
chain.dispense(cur);
}
}
}
如果其中一个链不能完全处理它,它将请求发送给链中的下一个处理器来处理剩余的请求。
如果处理器不能处理任何东西,它就将相同的请求转发给下一个链。
CreatingTheChain
public class Main {
public static void main(String[] args) {
// initialize the chain
IDispenseChain c1 = new Dollar50Dispenser();
IDispenseChain c2 = new Dollar20Dispenser();
IDispenseChain c3 = new Dollar10Dispenser();
// set the chain of responsibility
c1.setNextChain(c2);
c2.setNextChain(c3);
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
c1.dispense(new Currency(amount));
}
}
}
结果
Enter amount to dispense
80
Dispensing 1 50$ note
Dispensing 1 20$ note
Dispensing 1 10$ note
Enter amount to dispense
责任链模式在JDK源码中的应用
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
jtry-catch block
来看一个J2EE标准中常见的Filter类。
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException;
public void destroy();
}
这个Filter接口的定义非常简单,相当于责任链模式中的Handler抽象角色,那么它是如何形成一条责任链的呢?来看另外一个类,其实由doFilter()方法的最后一个参数可以看到其类型是FilterChain类,源码如下。
它把链条中的所有Filter都放到List中,然后在调用doFilter()方法时循环迭代List,也就是说List中的Filter会按顺序执行。