设计模式之责任链模式

前言

责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

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 中的责任链

References
posted @ 2021-01-21 21:35  胖大星-  阅读(302)  评论(0编辑  收藏  举报