网站首页 > 精选教程 正文
最近在做预算项目,预算占用的场景和责任链模式的应用场景类似,于是就查资料研究了下责任链模式,在这里给大家分享下
责任链模式的定义:
责任链模式将链中每一个节点都看作一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,
会沿着责任链的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止,属于行为型设计模式。
责任链模式的应用场景:
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
- 可动态指定一组对象处理请求。
责任链模式的UML图:
由上图可以看到责任链模式主要包含2个角色。
- 抽象处理者(Handler):定义一个请求处理的方法,并维护一个下一处理节点Handler对象。
- 具体处理者(ConcreteHandler):对请求进行处理,如果不感兴趣,则进行转发。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解的是其模式而不是其具体的实现。
责任链模式的独到之处是将其节点处理者组合成链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
使用责任链模式设计热插拔权限控制:
首先创建一个实体类Member。
public class Member {
private String loginName;
private String loginPass;
private String roleName;
public Member(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLoginPass() {
return loginPass;
}
public void setLoginPass(String loginPass) {
this.loginPass = loginPass;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Member{" +
"loginName='" + loginName + '\'' +
", loginPass='" + loginPass + '\'' +
", roleName='" + roleName + '\'' +
'}';
}
}
然后写一段我们经常写的代码,登录以及权限验证,然后返回。
public class MemberService {
/**
* 执行用户登录操作
*
* @param loginName 登录用户名
* @param loginPass 登录密码
*/
public void login(String loginName, String loginPass) {
// 检查用户名和密码是否为空
if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(loginPass)) {
System.out.println("用户名和密码为空,无法进行登录操作");
return;
}
System.out.println("用户名和密码均已提供,可继续执行后续流程");
// 检查用户是否存在
Member member = checkExists(loginName, loginPass);
if (member == null) {
System.out.println("指定的用户不存在,请确认信息后重试");
return;
}
System.out.println("登录成功!欢迎您的使用");
// 检查用户是否具有管理员权限
if (!"管理员".equals(member.getRoleName())) {
System.out.println("您并非管理员角色,不具备相应的操作权限");
return;
}
System.out.println("您具备管理员权限,允许进行操作");
}
/**
* 检查指定用户名和密码的用户是否存在
*
* @param loginName 登录用户名
* @param loginPass 登录密码
* @return 若用户存在则返回对应的 Member 对象,否则返回 null
*/
private Member checkExists(String loginName, String loginPass) {
Member member = new Member(loginName, loginPass);
member.setRoleName("管理员");
return member;
}
public static void main(String[] args) {
MemberService service = new MemberService();
service.login("tom", "666");
}
}
看上面的代码,虽然只有一个主方法login(),但是实际上我们做了几件事情,首选判空,然后判断用户是否存在,接着又验证用户的权限,最后
返回。这样写虽然也能达到目的,但是代码看着就很臃肿,并且耦合性很大,其中一个逻辑需要改变就需要修改整个方法。我们来看看用责任链模式
怎么解决这个问题:
首先创建一个Handler类。
/**
* 抽象处理者类,定义了处理成员对象的基本结构和链式处理机制
*/
public abstract class Handler {
// 指向下一个处理者的引用,用于构建处理链
protected Handler next;
/**
* 设置当前处理者的下一个处理者
*
* @param next 下一个处理者对象
*/
public void setNextHandler(Handler next) {
this.next = next;
}
/**
* 抽象方法,由具体的处理者子类实现,用于处理成员对象
*
* @param member 需要处理的成员对象
*/
public abstract void handleMember(Member member);
}
然后分别创建非空校验ValidateHandler、登录校验LoginHandler和权限校验AuthHandler类。
/**
* 验证处理者类,负责验证成员对象的用户名和密码是否为空
*/
public class ValidateHandler extends Handler {
/**
* 处理成员对象的验证逻辑
*
* @param member 需要处理的成员对象
*/
@Override
public void handleMember(Member member) {
// 检查用户名和密码是否为空
if (StringUtils.isEmpty(member.getLoginName()) || StringUtils.isEmpty(member.getLoginPass())) {
System.out.println("用户名和密码为空,无法继续处理");
return;
}
System.out.println("用户名和密码均已提供,可继续后续处理流程");
// 将处理任务传递给下一个处理者
if (next != null) {
next.handleMember(member);
}
}
}
/**
* 登录处理者类,负责模拟成员对象的登录操作
*/
public class LoginHandler extends Handler {
/**
* 处理成员对象的登录逻辑
*
* @param member 需要处理的成员对象
*/
@Override
public void handleMember(Member member) {
System.out.println("登录操作已成功完成!");
// 设置成员对象的角色为管理员
member.setRoleName("管理员");
// 将处理任务传递给下一个处理者
if (next != null) {
next.handleMember(member);
}
}
}
/**
* 权限验证处理者类,负责验证成员对象是否具有管理员权限
*/
public class AuthHandler extends Handler {
/**
* 处理成员对象的权限验证逻辑
*
* @param member 需要处理的成员对象
*/
@Override
public void handleMember(Member member) {
// 检查成员对象是否为管理员角色
if (!"管理员".equals(member.getRoleName())) {
System.out.println("您并非管理员角色,不具备相应操作权限");
return;
}
System.out.println("您具备管理员权限,允许进行操作");
}
}
接着修改MemberService的代码,我们需要将前面定义好的几个Handler根据业务需求串联起来,形成一条链即可。
public class MemberService {
/**
* 执行用户登录流程,通过责任链模式依次处理验证、登录和权限认证
*
* @param loginName 登录使用的用户名
* @param loginPass 登录使用的密码
*/
public void performLogin(String loginName, String loginPass) {
// 初始化验证处理者
Handler validationHandler = new ValidateHandler();
// 初始化登录处理者
Handler loginProcessHandler = new LoginHandler();
// 初始化权限认证处理者
Handler authorizationHandler = new AuthHandler();
// 构建责任链,将验证处理者的下一个处理者设置为登录处理者
validationHandler.setNextHandler(loginProcessHandler);
// 将登录处理者的下一个处理者设置为权限认证处理者
loginProcessHandler.setNextHandler(authorizationHandler);
// 创建成员对象并从验证处理者开始执行处理流程
validationHandler.handleMember(new Member(loginName, loginPass));
}
}
最后编写客户端调用代码:
public class Test {
/**
* 程序入口,用于测试会员服务的登录功能
*
* @param args 命令行参数
*/
public static void main(String[] args) {
// 实例化会员服务对象
MemberService memberServiceInstance = new MemberService();
// 调用会员服务的登录方法,尝试使用指定的用户名和密码进行登录
memberServiceInstance.performLogin("admin", "666");
}
}
这样写之后,各个模块之间就完全解耦,符合开闭原则。其实我们平时使用的很多权限校验框架都是运用这个原理,将各个维度的权限处理解耦之后
再串联起来,只处理各自相关的职责。如果职责与自己不相关,则抛给链上的下一个Handler。
责任链模式和建造者模式结合使用:
因为责任链模式具备链式结构,在上面的代码中,负责组装链式结构的MemberService类,如果业务有变,每次都要修改,且逻辑不清晰。我们可以通过
建造者模式来对其进行改造,首选修改Handler的代码:
/**
* 泛型抽象处理者类,用于构建处理成员对象的责任链
*
* @param <T> 泛型类型参数
*/
public abstract class Handler<T> {
// 指向下一个处理者的引用,用于构建责任链
protected Handler<T> nextHandler;
/**
* 设置当前处理者的下一个处理者
*
* @param next 下一个处理者对象
*/
public void setNextHandler(Handler<T> next) {
this.nextHandler = next;
}
/**
* 抽象方法,由具体的处理者子类实现,用于处理成员对象
*
* @param member 需要处理的成员对象
*/
public abstract void handleMember(Member member);
/**
* 静态内部类,用于构建处理者责任链
*
* @param <T> 泛型类型参数
*/
public static class Builder<T> {
// 责任链的头处理者
private Handler<T> chainHead;
// 责任链的尾处理者
private Handler<T> chainTail;
/**
* 向责任链中添加处理者
*
* @param handler 要添加的处理者对象
* @return 当前构建器实例,用于链式调用
*/
public Builder<T> appendHandler(Handler<T> handler) {
if (this.chainHead == null) {
// 若责任链为空,将该处理者设置为头和尾处理者
this.chainHead = this.chainTail = handler;
} else {
// 若责任链不为空,将该处理者添加到链尾
this.chainTail.setNextHandler(handler);
this.chainTail = handler;
}
return this;
}
/**
* 构建并返回责任链的头处理者
*
* @return 责任链的头处理者
*/
public Handler<T> constructChain() {
return this.chainHead;
}
}
}
再修改MemberService的代码:
public class MemberService {
/**
* 执行会员登录操作,借助责任链模式依次处理登录流程中的各项检查与操作
*
* @param loginName 会员登录使用的用户名
* @param loginPass 会员登录使用的密码
*/
public void executeLogin(String loginName, String loginPass) {
// 初始化责任链构建器
Handler.Builder<Member> chainBuilder = new Handler.Builder<>();
// 向责任链中依次添加验证处理者、登录处理者和权限认证处理者
chainBuilder.appendHandler(new ValidateHandler())
.appendHandler(new LoginHandler())
.appendHandler(new AuthHandler());
// 构建责任链并从链头开始处理会员登录请求
Handler<Member> chainHead = chainBuilder.constructChain();
chainHead.handleMember(new Member(loginName, loginPass));
}
}
责任链模式的优点:
- 将请求与处理解耦。
- 请求处理者只需要关注自己感兴趣的请求进行处理,对于不感兴趣的请求,之间转发给下一个节点处理。
- 具备链式传递请求功能,请求发送者不需要知晓链路结构,只需等待请求处理结果即可。
- 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
- 易于扩展新的请求处理类,符合开闭原则。
责任链模式的缺点;
- 责任链太长或者处理时间过长,会影响整体性能。
- 如果节点对象存在循环引用,则会造成死循环,导致系统崩溃。
- 上一篇: Java设计模式在真实项目中的生动体现
- 下一篇: Java多线程编程中的线程池:任务管理的艺术
猜你喜欢
- 2025-06-09 Java设计模式在真实项目中的生动体现
- 2025-06-09 Java设计模式:工厂模式与抽象工厂模式深度解读
- 2025-06-09 设计模式:Java开发者的"武功秘籍",让你的代码从青铜到王者!
- 2025-06-09 Java设计模式:软件设计的艺术画布
- 2025-06-09 Java设计模式在实际开发中的奇妙应用
- 2025-06-09 Java设计模式在Spring框架中的精彩演绎
- 2025-06-09 Java开发中常见的设计误区(java设计原则详解)
- 2025-06-09 Java高可用架构设计:构建稳定可靠的系统
- 2025-06-09 Java设计原则与重构:优雅代码的艺术
- 2025-06-09 Java 常见设计模式及应用场景(java 常见设计模式及应用场景有哪些)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)