一、定义

责任链模式(Chain of Responseiblibity Pattrern) 是将链中每一个节点看做是一个对象, 每个节点处理的请求均不同, 且内部自动维护一个下一节点对象. 当一个请求从链式的首端发出时, 会沿着链的路径依次传递给每一个节点对象, 直至有对象处理这个请求为止.

属于行为型设计模式

二、适用场景

  1. 多个对象可以处理同一请求, 但具体由哪个对象处理则在运行时动态决定.
  2. 在不明确指定接收者的情况下, 向多个对象中的一个提交一个请求.
  3. 可动态指定一组对象处理请求.

三、java代码简单案例

此处使用用户登录及认证做一个简单案例

使用责任链模式之前

/**
 * 用户实体类
 */
@Data
public class User {
    private String loginName;
    private String loginPass;
    private String roleName;

    public User(String loginName, String loginPass) {
        this.loginName = loginName;
        this.loginPass = loginPass;
    }
    
    @Override
    public String toString() {
        return "Member{" +
                "loginName='" + loginName + '\'' +
                ", loginPass='" + loginPass + '\'' +
                ", roleName='" + roleName + '\'' +
                '}';
    }
}
/**
 * 用户业务实现类
 */
public class UserService {

    public void login(String loginName,String loginPass){
        if(StringUtils.isEmpty(loginName) ||
                StringUtils.isEmpty(loginPass)){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");

        User user = checkExists(loginName,loginPass);
        if(null == user){
            System.out.println("用户不存在");
            return;
        }
        System.out.println("登录成功!");

        if(!"管理员".equals(user.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");

    }

    private User checkExists(String loginName, String loginPass){
        User user = new User(loginName,loginPass);
        user.setRoleName("管理员");
        return user;
    }

    public static void main(String[] args) {
        UserService service = new UserService();
        service.login("tom","666");
    }
}

以上, 在实现用户登录业务逻辑的时候, 各种校验于代码中... 可能还会有其他的业务校验, 就会造成代码长度过大, 非常复杂.

使用责任链模式之后

/**
 * 业务处理接口, 结合了建造者模式
 */
public abstract class Handler<T> {
    protected Handler<T> next;
    public void next(Handler next){ this.next = next;}

    public abstract void doHandler(User user);

    public static class Builder<T>{
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler handler){
            //do {
                if (this.head == null) {
                    this.head = this.tail = handler;
                    return this;
                }
                this.tail.next(handler);
                this.tail = handler;
            //}while (false);//真正框架中,如果是双向链表,会判断是否已经到了尾部
            return this;
        }

        public Handler<T> build(){
            return this.head;
        }
    }
}
/**
 * Handler实现类, 该Handler用于处理登录成功后的逻辑
 */
public class LoginHandler extends Handler {
    public void doHandler(User user) {
        System.out.println("登录成功!准备跳转首页...");
        
        // 登录成功后的业务逻辑......
        
        if(null != next) {
            next.doHandler(user);
        }
    }
}
/**
 * 权限认证Handler实现类
 */
public class AuthHandler extends Handler {
    public void doHandler(User user) {
        if(!"管理员".equals(user.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");
        if(null != next) {
            next.doHandler(user);
        }
    }
}
/**
 * 用户名密码校验
 */
public class ValidateHandler extends Handler {
    public void doHandler(User user) {
        if(StringUtils.isEmpty(user.getLoginName()) ||
                StringUtils.isEmpty(user.getLoginPass())){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");
        if(null != next) {
            next.doHandler(user);
        }
    }
}
/**
 * 用户Service层
 */
public class UserService {

    public void login(String loginName,String loginPass){

        Handler.Builder builder = new Handler.Builder();

        builder.addHandler(new ValidateHandler())
                .addHandler(new LoginHandler())
                .addHandler(new AuthHandler());

        User user = new User(loginName, loginPass);
        user.setRoleName("管理员");
        builder.build().doHandler(user);

        //用过Netty的人,肯定见过
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.login("tom","666");
    }
}

测试结果

------------------------------------------------------
用户名和密码不为空,可以往下执行
登录成功!
允许操作
------------------------------------------------------

四、优点

  1. 将请求与处理解耦.
  2. 请求矗立着(节点对象) 只需关注自己感兴趣的请求进行处理即可, 对不感兴趣的请求, 直接转发给下一级节点对象.
  3. 具备链式传递处理请求功能, 请求发送者无需知晓链路结构, 只需等待请求处理结果.
  4. 链路结构灵活, 可以通过改变链路结构动态地新增或删减责任.
  5. 易于扩展新的请求处理类(节点), 符合开闭原则.

五、缺点

  1. 责任链太长或者处理时间过长, 会影响整体性能,
  2. 如果节点对象存在循环引用时, 会造成死循环, 导致系统崩溃.
最后修改:2022 年 06 月 23 日
如果觉得我的文章对你有用,请点个赞吧~