设计模式之责任链模式
前言
责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
request -> 处理器1 -> 处理器2 -> 处理器3 -> 返回结果
比如财务审批系统,组长可以审批一千元,部门经理审批一千到一万元的,ceo任意金额的额度。每个审核者只关心自己责任范围内的请求,并且处理它。对于超出自己责任范围的,扔给下一个审核者处理,这样,将来继续添加审核者的时候,不用改动现有逻辑。
代码实现
请求对象:
@Data
@AllArgsConstructor
public class User {
private String name;
private BigDecimal money;
}
抽象的处理器:
public interface Handler {
Boolean process(User user);
}
具体处理器 First,Second,Third
public class FirstManagerHandler implements Handler {
@Override
public Boolean process(User user) {
// 超过一千元 处理不了
if (user.getMoney().compareTo(BigDecimal.valueOf(1000)) > 0) {
return null;
}
return true;
}
}
public class SecondManagerHandler implements Handler {
@Override
public Boolean process(User user) {
// 超过一万元 处理不了
if (user.getMoney().compareTo(BigDecimal.valueOf(10000)) > 0) {
return null;
}
return true;
}
}
public class ThirdManagerHandler implements Handler {
@Override
public Boolean process(User user) {
// 永远可以审批
return true;
}
}
处理链逻辑:
public class HandlerChain {
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
handlers.add(handler);
}
public boolean process(User user) {
for (Handler handler : handlers) {
Boolean isAccess = handler.process(user);
if (isAccess != null) {
return isAccess;
}
}
throw new RuntimeException("没有人能处理");
}
}
测试类:
public class HandlerChainTest {
public static void main(String[] args) {
// 构建处理链
HandlerChain chain = new HandlerChain();
chain.addHandler(new FirstManagerHandler());
chain.addHandler(new SecondManagerHandler());
chain.addHandler(new ThirdManagerHandler());
chain.process(new User("xiaoming", BigDecimal.valueOf(1000.1)));
}
}
有些责任链的实现方式是通过某个Handler手动调用下一个Handler来传递Request
public class HandlerV2 implements Handler {
private Handler next;
@Override
public Boolean process(User user) {
if (user.getMoney().compareTo(BigDecimal.valueOf(1000)) > 0) {
return true;
} else {
return next.process(user);
}
}
}
还有一些责任链模式,每个Handler都有机会处理Request,通常这种责任链被称为拦截器(Interceptor)或者过滤器(Filter),它的目的不是找到某个Handler处理掉Request,而是每个Handler都做一些工作
例如,JavaEE的Servlet规范定义的Filter就是一种责任链模式,它不但允许每个Filter都有机会处理请求,还允许每个Filter决定是否将请求“放行”给下一个Filter(接下来说的管道模式)
public class AuditFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
log(req);
if (check(req)) {
// 放行:
chain.doFilter(req, resp);
} else {
// 拒绝:
sendError(resp);
}
}
}
这种模式不但允许一个Filter自行决定处理ServletRequest和ServletResponse,还可以“伪造”ServletRequest和ServletResponse以便让下一个Filter处理,能实现非常复杂的功能。
管道模式
管道模式(Pipeline Pattern) 是责任链模式(Chain of Responsibility Pattern)的常用变体之一。在管道模式中,管道扮演着流水线的角色,将数据传递到一个加工处理序列中,数据在每个步骤中被加工处理后,传递到下一个步骤进行加工处理,直到全部步骤处理完毕。
纯的责任链模式在链上只会有一个处理器用于处理数据,而管道模式上多个处理器都会处理数据。
何时使用管道模式
任务代码较为复杂,需要拆分为多个子步骤时,尤其是后续可能在任意位置添加新的子步骤、删除旧的子步骤、交换子步骤顺序,可以考虑使用管道模式。
源码应用中可参考 Netty中的责任链 Logback 中的责任链