介绍:
职责链模式(chain of responsibility pattern) 定义: 是将链中的每一个节点看着一个对象,每个节点出来的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首段出发时,会沿着链的路径依次传递给每一个节点,直到有对象处理这个请求为止。属于行为模式。
在职责链模式中,多个处理器(也就是刚刚定义中说的“节点对象”)依次处理同一个请 求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再 传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职 责,所以叫作职责链模式。
使用场景:
在日常生活中责任链模式还是比较常见的,我们工作平时工作中的审批流程。往往都是一级一级的审批的。直到所有的流程审批完成在算审批完成;比如项目中的不同权限的校验,不同的权限校验可以构成一条责任链,请求沿着这条链传递,直到有一个校验器通过或者全部校验失败。
责任链主要是为了解耦请求与处理,客户只需要将请求发送到链路上即可,无需关注处理的处理细节。请求会自动的流转到一个节点直到流程走完。
原理:
职责链模式结构
职责链模式主要包含以下角色:
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,比如上图中的successor) 。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
案例:
责任链模式的实现非常简单,每一个具体的处理类都会保存在它之后的下一个处理类。当处理完成后,就会调用设置好的下一个处理类,直到最后一个处理类不再设置下一个处理类,这时处理链条全部完成。
利用责任链模式实现的简单登录验证:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Member implements Serializable {
/**
* 登录名
*/
private String loginName;
/**
* 登录通行证
*/
private String loginPass;
/**
* 角色名称
*/
private String roleName;
}
/**
* 处理程序
*
* @date 2024-05-30
*/
public abstract class Handler {
protected Handler next;
public void next(Handler next){ this.next = next;}
public abstract void doHandler(Member member);
}
/**
* 身份验证处理程序
*
* @author yulang
* @date 2024-05-30
*/
@Slf4j(topic = "authHandler")
public class AuthHandler extends Handler {
private static final String NAME_ROLE = "管理员";
/**
* 处理程序
*
* @param member 成员
*/
@Override
public void doHandler(Member member) {
if(!NAME_ROLE.equals(member.getRoleName())){
log.info("您不是管理员,没有操作权限");
return;
}
log.info("允许操作");
}
}
/**
* 登录处理程序
*
* @author yulang
* @date 2024-05-30
*/
@Slf4j(topic = "LoginHandler")
public class LoginHandler extends Handler {
@Override
public void doHandler(Member member) {
log.info("登录成功!");
member.setRoleName("管理员");
next.doHandler(member);
}
}
/**
* 验证处理程序
*
* @author yulang
* @date 2024-05-30
*/
@Slf4j(topic = "ValidateHandler")
public class ValidateHandler extends Handler {
@Override
public void doHandler(Member member) {
if(StringUtils.isEmpty(member.getLoginName()) ||
StringUtils.isEmpty(member.getLoginPass())){
log.info("用户名和密码为空");
return;
}
log.info("用户名和密码不为空,可以往下执行");
next.doHandler(member);
}
}
/**
* 会员服务
*
* @author yulang
* @date 2024-05-30
*/
public class MemberService {
public void login(String loginName,String loginPass){
Handler validateHandler = new ValidateHandler();
Handler loginHandler = new LoginHandler();
Handler authHandler = new AuthHandler();
validateHandler.next(loginHandler);
loginHandler.next(authHandler);
validateHandler.doHandler(new Member(loginName,loginPass,""));
}
}
测试代码
public static void main(String[] args) {
MemberService memberService = new MemberService();
memberService.login("zhangsan","000000");
}
职责链模式的缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。