免费注册网站网址,建筑公司网址,威海网络科技有限公司,网站建设培训教程新手入门到精通职责链模式
1 职责链模式介绍
职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求.将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止.
在职责链模式中#xff0c…职责链模式
1 职责链模式介绍
职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求.将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止.
在职责链模式中多个处理器也就是刚刚定义中说的“接收对象”依次处理同一个请 求。一个请求先经过 A 处理器处理然后再把请求传递给 B 处理器B 处理器处理完后再 传递给 C 处理器以此类推形成一个链条。链条上的每个处理器各自承担各自的处理职 责所以叫作职责链模式。 2 职责链模式原理
职责链模式结构 职责链模式主要包含以下角色:
抽象处理者Handler角色定义一个处理请求的接口包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,比如上图中的successor) 。具体处理者Concrete Handler角色实现抽象处理者的处理方法判断能否处理本次请求如果可以处理请求则处理否则将该请求转给它的后继者。客户类Client角色创建处理链并向链头的具体处理者对象提交请求它不关心处理细节和请求的传递过程。
3 职责链模式实现
责任链模式的实现非常简单每一个具体的处理类都会保存在它之后的下一个处理类。当处理完成后就会调用设置好的下一个处理类直到最后一个处理类不再设置下一个处理类这时处理链条全部完成。
public class RequestData {private String data;public RequestData(String data) {this.data data;}public String getData() {return data;}public void setData(String data) {this.data data;}
}/*** 抽象处理者类**/
public abstract class Handler {protected Handler successor null;public void setSuccessor(Handler successor){this.successor successor;}public abstract void handle(RequestData requestData);
}public class HandlerA extends Handler {Overridepublic void handle(RequestData requestData) {System.out.println(HandlerA 执行代码逻辑! 处理: requestData.getData());requestData.setData(requestData.getData().replace(A,));if(successor ! null){successor.handle(requestData);}else{System.out.println(执行中止!);}}
}public class HandlerB extends Handler {Overridepublic void handle(RequestData requestData) {System.out.println(HandlerB 执行代码逻辑! 处理: requestData.getData());requestData.setData(requestData.getData().replace(B,));if(successor ! null){successor.handle(requestData);}else{System.out.println(执行中止!);}}
}public class HandlerC extends Handler {Overridepublic void handle(RequestData requestData) {System.out.println(HandlerC 执行代码逻辑! 处理: requestData.getData());requestData.setData(requestData.getData());if(successor ! null){successor.handle(requestData);}else{System.out.println(执行中止!);}}
}public class Client {public static void main(String[] args) {Handler h1 new HandlerA();Handler h2 new HandlerB();Handler h3 new HandlerC();h1.setSuccessor(h2);h2.setSuccessor(h3);RequestData requestData new RequestData(请求数据ABCDE);h1.handle(requestData);}}4 职责链模式应用实例
接下来我们模拟有一个双11期间,业务系统审批的流程,临近双十一公司会有陆续有一些新的需求上线,为了保证线上系统的稳定,我们对上线的审批流畅做了严格的控制.审批的过程会有不同级别的负责人加入进行审批(平常系统上线只需三级负责人审批即可,双十一前后需要二级或一级审核人参与审批),接下来我们就使用职责链模式来设计一下此功能. 不使用设计模式
/*** 审核信息**/
public class AuthInfo {private String code;private String info ;public AuthInfo(String code, String... infos) {this.code code;for (String str : infos) {info this.info.concat(str );}}public String getCode() {return code;}public void setCode(String code) {this.code code;}public String getInfo() {return info;}public void setInfo(String info) {this.info info;}Overridepublic String toString() {return AuthInfo{ code code \ , info info \ };}
}/*** 模拟审核服务**/
public class AuthService {//审批信息 审批人Id申请单Idprivate static MapString,Date authMap new HashMapString, Date();/*** 审核流程* param uId 审核人id* param orderId 审核单id*/public static void auth(String uId, String orderId){System.out.println(进入审批流程,审批人ID: uId);authMap.put(uId.concat(orderId),new Date());}//查询审核结果public static Date queryAuthInfo(String uId, String orderId){return authMap.get(uId.concat(orderId)); //key审核人id审核单子id}
}public class AuthController {//审核接口public AuthInfo doAuth(String name, String orderId, Date authDate) throws ParseException {//三级审批Date date null;//查询是否存在审核信息,查询条件: 审核人ID订单ID,返回Map集合中的Datedate AuthService.queryAuthInfo(1000013, orderId);//如果为空,封装AuthInfo信息(待审核)返回if(date null){return new AuthInfo(0001,单号: orderId,状态: 等待三级审批负责人进行审批);}//二级审批SimpleDateFormat f new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);// 时间格式化//二级审核人主要审核双十一之前, 11-01 ~ 11-10号的请求,所以要对传入的审核时间进行判断//审核时间 大于 2022-11-01 并且 小于 2022-11-10,Date1.after(Date2),当Date1大于Date2时返回TRUE,Date1.before(Date2)当Date1小于Date2时返回TRUEif(authDate.after(f.parse(2022-11-01 00:00:00)) authDate.before(f.parse(2022-11-10 00:00:00))){//条件成立,查询二级审核的审核信息date AuthService.queryAuthInfo(1000012,orderId);//如果为空,还是待二级审核人审核状态if(date null){return new AuthInfo(0001,单号: orderId,状态: 等待二级审批负责人进行审批);}}//一级审批//审核范围是在11-11日 ~ 11-31日if(authDate.after(f.parse(2022-11-11 00:00:00)) authDate.before(f.parse(2022-11-31 00:00:00))){date AuthService.queryAuthInfo(1000011,orderId);if(date null){return new AuthInfo(0001,单号: orderId,状态: 等待一级审批负责人进行审批);}}return new AuthInfo(0001,单号: orderId,申请人: name , 状态: 审批完成!);}
}public class Client {public static void main(String[] args) throws ParseException {AuthController controller new AuthController();SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);Date date sdf.parse(2022-11-12 00:00:00);//设置申请流程//三级审核//1.调用doAuth方法,模拟发送申请人相关信息AuthInfo info1 controller.doAuth(研发小周, 100001000010000, date);System.out.println(当前审核状态: info1.getInfo());/*** 2.模拟进行审核操作, 虚拟审核人ID: 1000013* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID*/AuthService.auth(1000013, 100001000010000);System.out.println(三级负责人审批完成,审批人: 王工);System.out.println();//二级审核//1.调用doAuth方法,模拟发送申请人相关信息AuthInfo info2 controller.doAuth(研发小周, 100001000010000, date);System.out.println(当前审核状态: info2.getInfo());/*** 2.模拟进行审核操作, 虚拟审核人ID: 1000012* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID*/AuthService.auth(1000012, 100001000010000);System.out.println(二级负责人审批完成,审批人: 张经理);System.out.println();//一级审核//1.调用doAuth方法,模拟发送申请人相关信息AuthInfo info3 controller.doAuth(研发小周, 100001000010000, date);System.out.println(当前审核状态: info3.getInfo());/*** 2.模拟进行审核操作, 虚拟审核人ID: 1000012* 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID*/AuthService.auth(1000011, 100001000010000);System.out.println(一级负责人审批完成,审批人: 罗总);}
}职责链模式重构代码
下图是为当前业务设计的责任链结构,统一抽象类AuthLink 下 有三个子类,将三个子类的执行通过编排,模拟出一条链路,这个链路就是业务中的责任链. /*** 抽象审核链类*/
public abstract class AuthLink {protected Logger logger LoggerFactory.getLogger(AuthLink.class);protected SimpleDateFormat f new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);protected String levelUserId; //审核人IDprotected String levelUserName; //审核人姓名protected AuthLink next; //持有下一个处理类的引用public AuthLink(String levelUserId, String levelUserName) {this.levelUserId levelUserId;this.levelUserName levelUserName;}//获取下一个处理类public AuthLink getNext() {return next;}//责任链中添加处理类public AuthLink appendNext(AuthLink next) {this.next next;return this;}//抽象审核方法public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}/** 一级负责人*/
public class Level1AuthLink extends AuthLink {private Date beginDate f.parse(2020-11-11 00:00:00);private Date endDate f.parse(2020-11-31 23:59:59);public Level1AuthLink(String levelUserId, String levelUserName) throws ParseException {super(levelUserId, levelUserName);}Overridepublic AuthInfo doAuth(String uId, String orderId, Date authDate) {Date date AuthService.queryAuthInfo(levelUserId, orderId);if (null date) {return new AuthInfo(0001, 单号, orderId, 状态待一级审批负责人 , levelUserName);}AuthLink next super.getNext();if (null next) {return new AuthInfo(0000, 单号, orderId, 状态一级审批完成, 时间, f.format(date), 审批人, levelUserName);}if (authDate.before(beginDate) || authDate.after(endDate)) {return new AuthInfo(0000, 单号, orderId, 状态一级审批完成, 时间, f.format(date), 审批人, levelUserName);}return next.doAuth(uId, orderId, authDate);}
}/*** 二级负责人*/
public class Level2AuthLink extends AuthLink {private Date beginDate f.parse(2020-11-11 00:00:00);private Date endDate f.parse(2020-11-31 23:59:59);public Level2AuthLink(String levelUserId, String levelUserName) throws ParseException {super(levelUserId, levelUserName);}public AuthInfo doAuth(String uId, String orderId, Date authDate) {Date date AuthService.queryAuthInfo(levelUserId, orderId);if (null date) {return new AuthInfo(0001, 单号, orderId, 状态待二级审批负责人 , levelUserName);}AuthLink next super.getNext();if (null next) {return new AuthInfo(0000, 单号, orderId, 状态二级审批完成, 时间, f.format(date), 审批人, levelUserName);}if (authDate.before(beginDate) || authDate.after(endDate) ) {return new AuthInfo(0000, 单号, orderId, 状态二级审批完成, 时间, f.format(date), 审批人, levelUserName);}return next.doAuth(uId, orderId, authDate);}}/*** 三级负责人*/
public class Level3AuthLink extends AuthLink {public Level3AuthLink(String levelUserId, String levelUserName) {super(levelUserId, levelUserName);}public AuthInfo doAuth(String uId, String orderId, Date authDate) {Date date AuthService.queryAuthInfo(levelUserId, orderId);if (null date) {return new AuthInfo(0001, 单号, orderId, 状态待三级审批负责人 , levelUserName);}AuthLink next super.getNext();if (null next) {return new AuthInfo(0000, 单号, orderId, 状态三级审批完成, 时间, f.format(date), 审批人, levelUserName);}return next.doAuth(uId, orderId, authDate);}}
测试
public class Client {private Logger logger LoggerFactory.getLogger(ApiTest.class);Testpublic void test_AuthLink() throws ParseException {AuthLink authLink new Level3AuthLink(1000013, 王工).appendNext(new Level2AuthLink(1000012, 张经理).appendNext(new Level1AuthLink(1000011, 段总)));SimpleDateFormat f new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);Date currentDate f.parse(2020-11-18 23:49:46);logger.info(测试结果{}, JSON.toJSONString(authLink.doAuth(研发牛马, 1000998004813441, currentDate)));// 模拟三级负责人审批AuthService.auth(1000013, 1000998004813441);logger.info(测试结果{}, 模拟三级负责人审批王工);logger.info(测试结果{}, JSON.toJSONString(authLink.doAuth(研发牛马, 1000998004813441, currentDate)));// 模拟二级负责人审批AuthService.auth(1000012, 1000998004813441);logger.info(测试结果{}, 模拟二级负责人审批张经理);logger.info(测试结果{}, JSON.toJSONString(authLink.doAuth(研发牛马, 1000998004813441, currentDate)));// 模拟一级负责人审批AuthService.auth(1000011, 1000998004813441);logger.info(测试结果{}, 模拟一级负责人审批段总);logger.info(测试结果{}, JSON.toJSONString(authLink.doAuth(研发牛马, 1000998004813441, currentDate)));}
}从上面的代码结果看,我们的责任链已经生效,按照责任链的结构一层一层审批.当工作流程发生变化可以动态地改变链内的成员或者修改它们的次序也可动态地新增或者删除责任。并且每个类只需要处理自己该处理的工作不能处理的传递给下一个对象完成明确各类的责任范围符合类的单一职责原则。
5 职责链模式总结
职责链模式的优点 降低了对象之间的耦合度 该模式降低了请求发送者和接收者的耦合度。 增强了系统的可扩展性 可以根据需要增加新的请求处理类满足开闭原则。 增强了给对象指派职责的灵活性 当工作流程发生变化可以动态地改变链内的成员或者修改它们的次序也可动态地新增或者删除责任。 责任链简化了对象之间的连接 一个对象只需保持一个指向其后继者的引用不需保持其他所有处理者的引用这避免了使用众多的 if 或者 if···else 语句。 责任分担 每个类只需要处理自己该处理的工作不能处理的传递给下一个对象完成明确各类的责任范围符合类的单一职责原则。
职责链模式的缺点:
不能保证每个请求一定被处理。由于一个请求没有明确的接收者所以不能保证它一定会被处理该请求可能一直传到链的末端都得不到处理。对比较长的职责链请求的处理可能涉及多个处理对象系统性能将受到一定影响。职责链建立的合理性要靠客户端来保证增加了客户端的复杂性可能会由于职责链的错误设置而导致系统出错如可能会造成循环调用。
使用场景分析
责任链模式常见的使用场景有以下几种情况。
在运行时需要动态使用多个关联对象来处理同一次请求时。比如请假流程、员工入职流程、编译打包发布上线流程等。不想让使用者知道具体的处理逻辑时。比如做权限校验的登录拦截器。需要动态更换处理对象时。比如工单处理系统、网关 API 过滤规则系统等。职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能.