责任链模式
责任链模式(Chain of Responsibility Pattern):是指将链中的每一个节点看作是一个对象,每个节点处理的请求均不同,且每个节点内部自动维护了一个又一个节点对象。当一个请求在链路的头部发出时,会沿着链的路径依次传递给每一个节点对象,直到有对象处理这个请求为止。
在我们一个系统中,登录及权限校验就可以作为一条“链路”来处理,普通写法就是在一个方法里面先校验账号密码是否正确,然后校验角色是否正确,再校验权限是否正确,但是如果利用责任链模式我们就可以把这三种校验封装成 3 个节点,并让这三个节点构成一条“链路”。示例我们就通过登录及其权限校验的示例来举例说明。
package cn.liangyy.chain;
/**
* 登录用户信息
* 存储一些需要校验的信息
*/
public class LoginUser {
//登录名
private String loginName;
//密码
private String password;
//角色
private String roleName;
//权限
private String permission;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
}
复制代码
package cn.liangyy.chain;
/**
* "链路"的抽象节点类
* 维护下一个节点,并定义执行业务逻辑
*/
public abstract class MyHandler {
//持有下一个节点对象,也就是每个节点都需要知道自己的下一个节点是谁才能传递下去
protected MyHandler next;
public void next(MyHandler handler){
this.next = handler;
}
//执行每个节点的处理逻辑
public abstract void doHandler(LoginUser loginUser);
}
复制代码
package cn.liangyy.chain;
/**
* 校验账户密码节点类
* "链路"节点之一,继承抽象节点类
*/
public class VerifyAccountHandler extends MyHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (null == loginUser.getLoginName()){
System.out.println("用户名不能为空!");
return;
}
if (null == loginUser.getPassword()){
System.out.println("密码不能为空!");
return;
}
if (!loginUser.getPassword().equals("123")){
System.out.println("密码不正确!");
return;
}
System.out.println("账户密码校验通过!");
//传递给下一个节点
next.doHandler(loginUser);
}
}
复制代码
package cn.liangyy.chain;
/**
* 校验角色信息节点类
* "链路"节点之一
*/
public class VerifyRolehandler extends MyHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (!"admin".equals(loginUser.getRoleName())){
//校验角色信息
System.out.println("角色信息有误!");
return;
}
System.out.println("角色信息校验通过");
//传递给下一个节点
next.doHandler(loginUser);
}
}
复制代码
package cn.liangyy.chain;
/**
* 校验权限信息节点类
* "链路"节点之一
*/
public class VerifyPermissionhandler extends MyHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (!"admin".equals(loginUser.getPermission())){
System.out.println("暂无权限!");
return;
}
System.out.println("权限校验通过,登录成功!");
}
}
复制代码
package cn.liangyy.chain;
/**
* 责任链模式-测试
*/
public class TestChain {
public static void main(String[] args) {
MyHandler accountHandler = new VerifyAccountHandler();
MyHandler roleHandler = new VerifyRolehandler();
MyHandler permissionHandler = new VerifyPermissionhandler();
accountHandler.next(roleHandler);
roleHandler.next(permissionHandler);
LoginUser loginUser = new LoginUser();
loginUser.setLoginName("liangsir");
loginUser.setPassword("123");
loginUser.setRoleName("admin");
loginUser.setPermission("admin");
//从起点开始调用
accountHandler.doHandler(loginUser);
}
}
复制代码
以上写法为责任链模式的常规写法,下面我们将用建造者模式进行改造,使其更加优雅...
package cn.liangyy.chain;
/**
* 登录用户信息
* 存储一些需要校验的信息
*/
public class LoginUser {
//登录名
private String loginName;
//密码
private String password;
//角色
private String roleName;
//权限
private String permission;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
}
复制代码
package cn.liangyy.chain.two;
import cn.liangyy.chain.one.LoginUser;
import cn.liangyy.chain.one.MyHandler;
/**
* "链路"的抽象节点
*/
public abstract class BuildHandler<T> {
//持有下一个节点对象,也就是每个节点都需要知道自己的下一个节点是谁才能传递下去
protected MyHandler next;
public void next(MyHandler handler){
this.next = handler;
}
//执行每个节点的处理逻辑
public abstract void doHandler(LoginUser loginUser);
}
复制代码
package cn.liangyy.chain.two;
/**
* "链路"对象的建造者类
*/
public class Builder<T> {
//链路的头节点
private BuildHandler<T> head;
//链路的尾节点
private BuildHandler<T> tail;
public Builder<T> addHandler(BuildHandler handler){
//如果头节点为空,则说明正在构建第一个节点,此时头尾节点都相等
if (null == head){
head = this.tail = handler;
return this;
}
//如果节点不为空
//把当前"链路"的tail节点的下一个节点指向刚加进来的节点
this.tail.next(handler);
//然后把当前加进来的节点设置为tail节点
this.tail = handler;
return this;
}
public BuildHandler<T> build(){
//调用build之后就会开始调用流程了,从头节点开始,所以返回头节点
return this.head;
}
}
复制代码
package cn.liangyy.chain.two;
/**
* 校验账号密码节点类
*/
public class VerifyAccountHandler extends BuildHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (null == loginUser.getLoginName()){
System.out.println("用户名不能为空!");
return;
}
if (null == loginUser.getPassword()){
System.out.println("密码不能为空!");
return;
}
if (!loginUser.getPassword().equals("123")){
System.out.println("密码不正确!");
return;
}
System.out.println("账户密码校验通过!");
//传递给下一个节点
next.doHandler(loginUser);
}
}
复制代码
package cn.liangyy.chain.two;
/**
* 校验角色信息节点类
* "链路"节点之一
*/
public class VerifyRolehandler extends BuildHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (!"admin".equals(loginUser.getRoleName())){
//校验角色信息
System.out.println("角色信息有误!");
return;
}
System.out.println("角色信息校验通过");
//传递给下一个节点
next.doHandler(loginUser);
}
}
复制代码
package cn.liangyy.chain.two;
/**
* 校验权限信息节点类
* "链路"节点之一
*/
public class VerifyPermissionhandler extends BuildHandler {
@Override
public void doHandler(LoginUser loginUser) {
if (!"admin".equals(loginUser.getPermission())){
System.out.println("暂无权限!");
return;
}
System.out.println("权限校验通过,登录成功!");
}
}
复制代码
package cn.liangyy.chain.two;
/**
* 责任链模式-测试
*/
public class TestBuildChain {
public static void main(String[] args) {
LoginUser loginUser = new LoginUser();
loginUser.setLoginName("liangsir");
loginUser.setPassword("123");
loginUser.setRoleName("admin");
loginUser.setPermission("admin");
Builder<BuildHandler> build = new Builder<>();
//利用建造者模式构建"链路对象"
build.addHandler(new VerifyAccountHandler())
.addHandler(new VerifyRolehandler())
.addHandler(new VerifyPermissionhandler());
//build方法返回头节点,所以从头节点开始执行,后面就会自动传递
build.build().doHandler(loginUser);
}
}
复制代码
可以看到,通过建造者模式和责任链模式结合的代码,在构造链路对象的时候比常规写法优雅多了...
责任链模式使用场景责任链模式主要是解耦了请求与处理,用户只需要将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点进行处理。主要适用于如下场景:
责任链模式优点
请求处理者(链路中的节点)只需关注自己感兴趣的请求进行处理,对于不感兴趣或者无法处理的请求直接转发给下一个处理者。
具备链式传递请求的功能,请求发送者无需知晓链路结构,只需等待请求处理结果。
链路结构灵活,可以通过改变链路结构动态的新增或者删减责任。
易于扩展新的请求处理类,符合开闭原则。
责任链模式缺点
评论