职责链模式
责任链模式
1.基本介绍
责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。
生活中的应用场景就是**「审批流」** 。责任链模式主要是解耦了请求与处理,客户只需将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。
传统的责任链示例:
AAAHandler.setNextHandler(deptManagerLeaveHandler);
directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
BBBHandler.setNextHandler(AAAHandler);
deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);
很难区分出谁是下一步,因此责任链通常搭配建造者模式一起使用。
2.职责链模式的原理类图
- 对原理类图的说明-即(职责链模式的角色及职责)
- Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外 Handler
- ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
- Request , 含义很多属性,表示一个请求
3.案例场景
下面写一个登录验证判断的例子,一般责任链模式会搭配着**「建造者模式」** 一起用,即**「链式编程」** 。因为这样链条看起来更加清晰明了,而传统的写法很抽象,很难看出谁谁谁在谁的前面,谁谁谁在谁的后面,如下所示:
AAAHandler.setNextHandler(deptManagerLeaveHandler);
directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
BBBHandler.setNextHandler(AAAHandler);
deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);
下面先创建一个 Handler 的抽象类,这个类里面有一个下一个 Handler 处理器 next,还有一个 Builder,这个就是用来构建链的,也是方便我们的链式编程。
public abstract class Handler<T> {
protected Handler next;
private void next(Handler next) {
this.next = next;
}
public abstract void doHandler(T t);
public static class Builder<T> {
private Handler<T> head;
private Handler<T> tail;
/**
* 链路维护
* @param handler
* @return
*/
public Builder<T> addHandler(Handler handler) {
if (this.head == null) {
this.head = this.tail = handler;
return this;
}
this.tail.next(handler);
//下一次进来指定tail的下一个handler
this.tail = handler;
return this;
}
public Handler<T> build() {
return this.head;
}
}
}
下面写非空校验 ValidateHandler 类,这里面先判断用户名和密码是否为空,空的话返回,非空的话判断 next 是否为空,非空的话就丢给下一个处理器去执行。
public class ValidateHandler extends Handler<Member> {
@Override
public void doHandler(Member member) {
if (StringUtils.isEmpty(member.getUsername()) ||
StringUtils.isEmpty(member.getPassword())) {
System.out.println("用户名和密码不能为空");
return;
}
if (null != next) {
next.doHandler(member);
}
}
}
创建登录检验LoginHandler类,判断账号密码是否正确
public class LoginHandler extends Handler<Member> {
@Override
public void doHandler(Member member) {
if (!"jack".equals(member.getUsername()) || !"666".equals(member.getPassword())) {
System.out.println("用户名密码不正确");
return;
}
if (null != next) {
next.doHandler(member);
}
}
}
创建权限检验 AuthHandler 类,判断角色是否有权限
public class AuthHandler extends Handler<Member> {
@Override
public void doHandler(Member member) {
if (!"管理员".equals(member.getRoleName())) {
System.out.println("您不是管理员,没有操作权限");
return;
}
if (null != next) {
next.doHandler(member);
}
}
}
创建执行业务逻辑类,也可以不写,通常放在serviceImpl实现类中
public class BusinessLogicHandler extends Handler<Member> {
@Override
public void doHandler(Member member) {
System.out.println("执行业务逻辑。。");
}
}
测试类
public class Test {
public static void main(String[] args) {
Handler.Builder builder = new Handler.Builder();
// 这里就是链式编程,谁在前谁在后看的清清楚楚,明明白白
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler())
.addHandler(new BusinessLogicHandler());
Member member = new Member();
member.setUsername("");
member.setPassword("");
builder.build().doHandler(member);
}
}
public class Test {
public static void main(String[] args) {
Handler.Builder builder = new Handler.Builder();
// 这里就是链式编程,谁在前谁在后看的清清楚楚,明明白白
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler())
.addHandler(new BusinessLogicHandler());
Member member = new Member();
member.setUsername("jack");
member.setPassword("666");
member.setRoleName("管理员");
builder.build().doHandler(member);
}
4.职责链模式的注意事项和细节
- 将请求和处理分开,实现解耦,提高系统的灵活性
- 简化了对象,使对象不需要知道链的结构
- 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能
- 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
- 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web 中 Tomcat
对 Encoding 的处理、拦截器