首页 > 编程笔记 > Java笔记

使用责任链模式实现热插拔权限控制

为了让小伙伴们加深对责任链模式的理解,本节我们使用责任链模式实现热插拔权限控制。

首先创建实体类 Member。
public class Member {
    private String username;
    private String password;
    private String roleName;

    public Member(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    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;
    }

    @Override
    public String toString() {
        return "Member{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", roleName='" + roleName + '\'' +
                '}';
    }
}
下面再来看一段我们经常使用的代码。
import org.springframework.util.StringUtils;

public class MemberService {
    public void login(String userName, String password) {
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以向下执行");
        System.out.println("用户名:" + userName + ",密码:" + password);
        Member member = checkExist(userName, password);
        if (null == member) {
            System.out.println("用户不存在");
            return;
        }
        System.out.println("登录成功!");
        if (!"管理员".equals(member.getRoleName())) {
            System.out.println("您不是管理员,没有该操作权限");
            return;
        }
        System.out.println("允许操作");

    }

    private Member checkExist(String userName, String password) {
        Member member = new Member(userName, password);
        member.setRoleName("管理员");
        return member;
    }

    public static void main(String[] args) {
        MemberService service = new MemberService();
        service.login("新宝库", "https://www.xinbaoku.com");
    }
}
运行结果如下:

用户名和密码不为空,可以向下执行
用户名:新宝库,密码:https://www.xinbaoku.com
登录成功!
允许操作

上面代码中,主要做了登录前的数据验证。其判断逻辑是有先后顺序的。首先做非空判断,检查用户名密码是否有效,然后获得用户角色,最后判断用户是否拥有该操作权限。这样的检验性代码一般都是必不可少的,但是写在具体的业务代码中又显得非常臃肿,这时可以使用责任链模式,将这些检查步骤串联起来,既不影响代码美观,还可以使我们在编码时更加专注于某一个具体的业务逻辑处理。

下面我们使用责任链模式来优化代码,首先创建一个 Handler 类。
public abstract class Handler {
    protected Handler chain;

    public void next(Handler handler) {
        this.chain = handler;
    }

    public abstract void doHandler(Member member);
}
然后分别创建非空校验 ValidateHandler 类、登录校验 LoginHandler 类和权限校验 AuthHandler 类。ValidateHandler 类的代码如下。
public class ValidateHandler extends Handler {
    public void doHandler(Member member) {
        if (StringUtils.isEmpty(member.getUsername()) ||
                StringUtils.isEmpty(member.getPassword())) {
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");
        System.out.println("用户名:" + member.getUsername() + ",密码:" + member.getPassword());
        chain.doHandler(member);
    }
}
LoginHandler 类的代码如下。
public class LoginHandler extends Handler {
    public void doHandler(Member member) {
        System.out.println("登录成功!");
        member.setRoleName("管理员");
        chain.doHandler(member);
    }
}
AuthHandler 类的代码如下。
public class AuthHandler extends Handler {
    public void doHandler(Member member) {
        if (!"管理员".equals(member.getRoleName())) {
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("您是管理员,允许操作");
    }
}
接着修改 MemberService 中的代码,将前面定义好的几个 Handler 根据业务需求串联起来,形成一条链即可。
public class MemberService {
    public void login(String userName, String password) {

        Handler validateHandler = new ValidateHandler();
        Handler loginHandler = new LoginHandler();
        Handler authHandler = new AuthHandler();

        validateHandler.next(loginHandler);
        loginHandler.next(authHandler);

        validateHandler.doHandler(new Member(userName, password));

    }
}
客户端测试代码如下。
public static void main(String[] args) {
    MemberService service = new MemberService();
    service.login("新宝库", "https://www.xinbaoku.com");
}
运行结果如下所示。

用户名和密码不为空,可以往下执行
用户名:新宝库,密码:https://www.xinbaoku.com
登录成功!
您是管理员,允许操作

我们平时使用的很多校验框架都是运用的这个原理,将各个维度的权限处理解耦之后再串联起来,只处理各自相关的职责。如果职责与自己不相关,则抛给链上的下一个 Handler,俗称“踢皮球”。

所有教程

优秀文章