首页 > 技术文章 > 设计模式-责任链模式

lihw-study 2021-09-04 11:18 原文

设计模式-责任链模式

定义

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

属于行为模式

适用场景

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

代码示例

普通写法

拿处理请求举例:

  1. 定义 Handler 抽象类,提供设置下一 handler 方法
package com.black.design.pattern.responsibilitychain.general;

// 抽象类
public abstract class Handler {

    protected Handler sucessor;
    
    public  void setNextHandler(Handler sucessor) {
        this.sucessor = sucessor;
    }

    public abstract  void handleRequest(String request) ;
    
}

  1. 定义 ConcreHandlerA 类,只能处理 requestA 请求,其他请求则让下一个处理类处理
package com.black.design.pattern.responsibilitychain.general;

public class ConcreHandlerA extends Handler {

    @Override
    public void handleRequest(String request) {

        if("requestA".equals(request)) {
            System.out.println(this.getClass().getSimpleName() +  "handle with request [" +request +"]");
            return;
        }
        if (this.sucessor != null) {
            sucessor.handleRequest(request);
        }
    }

}

  1. 定义 ConcreHandlerB 类,只能处理 requestB 请求,其他请求则让下一个处理类处理
package com.black.design.pattern.responsibilitychain.general;

public class ConcreHandlerB extends Handler {

    @Override
    public void handleRequest(String request) {
        if("requestB".equals(request)) {
            System.out.println(this.getClass().getSimpleName() +  "handle with request [" +request +"]");
            return;
        }
        if (this.sucessor != null) {
            sucessor.handleRequest(request);
        }
    }

}

  1. 测试
package com.black.design.pattern.responsibilitychain.general;
//测试类
public class HandlerTest {
    
    public static void main(String[] args) {
		// 实例化 handlerA 处理类
        Handler handlerA = new ConcreHandlerA();
		// 实例化 handlerB 处理类
        Handler handlerB = new ConcreHandlerB();
        // handlerA 下一节点是 handlerB 处理类
        handlerA.setNextHandler(handlerB);
        // 定义 3 个请求
        String[] reqs = {"requestA","requestB","requestC"};
        // 循环处理
        for (int i = 0; i < reqs.length; i++) {
            handlerA.handleRequest(reqs[i]);
        }
       
    }
}

结果:

ConcreHandlerAhandle with request [requestA]
ConcreHandlerBhandle with request [requestB]

登录场景

基本流程:

  1. 验证用户名和密码是否为空
  2. 登录验证,成功后获取用户权限
  3. 验证权限

代码如下:

  1. 登录接口

package com.black.design.pattern.responsibilitychain.auth;

// 登录接口类
public interface LoginService {

    // 根据用户名和密码登录
    public void login(String userName, String password);
}

package com.black.design.pattern.responsibilitychain.auth;

// 登录接口实现类
public class LoginServiceImpl implements LoginService {

    public void login(String userName, String password) {
        // 校验用户名密码是否为null 
        Handler vHandler = new ValidatorHandler();
        // 登录
        Handler loginHandler = new LoginHandler();
        // 校验是否有权限
        Handler authHandler = new AuthHandler();
        //执行
        vHandler.next(loginHandler);
        loginHandler.next(authHandler);
        vHandler.doHandle(new UserInfo(userName, password));
    }
}

package com.black.design.pattern.responsibilitychain.auth;

 // 用户信息
public class UserInfo {
    // 用户名
    private String userName;
    // 密码
    private String password;
    // 角色
    private String role;

    public UserInfo(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}


  1. 创建抽象处理类
package com.black.design.pattern.responsibilitychain.auth;

// 处理类
public abstract class Handler {

    // 下一处理类
    protected Handler nextHandler;
    
    // 处理方法
    protected  abstract void doHandle(UserInfo userInfo) ;
    
	// 设置下一处理
    public void next(Handler h) {
        this.nextHandler = h;
    }
}

  1. 登录参数校验处理类
package com.black.design.pattern.responsibilitychain.auth;

// 登录参数验证处理类
public class ValidatorHandler extends Handler {

    @Override
    protected void doHandle(UserInfo userInfo) {
        // 校验参数
        if(userInfo.getUserName() == null || 
                userInfo.getPassword() == null) {
            System.out.println("用户名或密码为空,不允许登录!");
            return;
        }
        System.out.println("用户名和密码不为空,继续");
       nextHandler.doHandle(userInfo);
    }

}

  1. 登录处理类
package com.black.design.pattern.responsibilitychain.auth;

// 登录处理类
public class LoginHandler extends Handler {

    @Override
    protected void doHandle(UserInfo userInfo) {

        System.out.println("登录成功!");
        // 登录成功设置用户权限
        //userInfo.setRole("业务员");
        userInfo.setRole("管理员");
        nextHandler.doHandle(userInfo);
    }
}

  1. 权限验证处理类
package com.black.design.pattern.responsibilitychain.auth;

// 权限验证处理类
public class AuthHandler extends Handler {

    @Override
    protected void doHandle(UserInfo userInfo) {

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

}

测试类

package com.black.design.pattern.responsibilitychain.auth;

// 测试类
public class AuthTest {

    public static void main(String[] args) {
        LoginService loginService = new LoginServiceImpl();
        loginService.login("black", "abc");
    }
}

测试结果:

用户名和密码不为空,继续
登录成功!
允许操作



优化版

主要优化点: 增加 Handler Builder 类,用于构建 Handler 处理链。只需要调整 Handler 类和 LoginServiceImpl 类即可。

package com.black.design.pattern.responsibilitychain.auth;

// 处理类
public abstract class Handler {

    // 下一处理类
    protected Handler nextHandler;
    
    // 处理
    protected  abstract void doHandle(UserInfo userInfo) ;
    
    public void next(Handler h) {
        this.nextHandler = h;
    }
    
    // 用于构建 handler 处理链
    public static  class Builder{
        
        private Handler first;// 首节点
        
        private Handler last;// 尾节点
        
        // 设置下一节点
        public Builder next(Handler handler) {
            if(first == null ) {
                // 如果 首节点是null 那么 handler 就是第一个节点
                first = last = handler;
            }
            // 如果 首节点不是null 那么 handler 就加入到最后一个节点
            last.next(handler);
            last = handler;
            return this;
        }
        
        public Handler build() {
            // 每次返回链的首节点
            return first;
        }
    }
}

package com.black.design.pattern.responsibilitychain.auth;

// 登录接口实现类
public class LoginServiceImpl implements LoginService {

    public void login(String userName, String password) {
        // 校验用户名密码是否为null 
        Handler vHandler = new ValidatorHandler();
        // 登录
        Handler loginHandler = new LoginHandler();
        // 校验是否有权限
        Handler authHandler = new AuthHandler();
        
        // 构建 handler 处理链
        Handler.Builder builder = new  Handler.Builder();
        builder.next(vHandler).next(loginHandler).next(authHandler);
        
     
        builder.build().doHandle(new UserInfo(userName, password));
    }
}

测试结果:

用户名和密码不为空,继续
登录成功!
允许操作

推荐阅读