这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
今天我们一起来学习,使用频率很高,且实战性比较强的一种模式----组合模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!
持续更新中......
话不多说,进入正题
责任链模式
责任链模式,重要的体现在这个链上面,从上到下,就是一条链式调用,A调B,B调C。
官方定义:通过为多个对象提供处理请求的机会,避免将请求的发送者与其接收者耦合。链接接收对象并沿着链传递请求,直到对象处理它。
注意:定义中说了一个关键点:通过构建一个处理流水线来对一次请求进行多次的处理。
前几天我在京东上遇到一个场景,去年买的耳机坏掉了,今天正好在有效期内,那么经过协商在京东申请售后。我仔细观察了他的状态。我先申请售后,然后客服给我打过来电话(不得不说京东服务真的是好),会先打开订单系统查询你提供的订单信息并确认是否正确,确认后再使用物流系统通知快递小哥上门取件,快递小哥取件后会返回商品让仓储系统进行确认,并通知商品系统……这样的一个过程就是责任链模式的真实应用。
在我们日常的开发中,一个经典的使用场景就是参数的判断,比如我们要判断A参数是否符合条件,B参数是否符合条件,接着C判断,如果都符合,接着往下走,去执行相关逻辑。
下面我们看下图
从该图中,我们能看出责任链模式其实只有两个关键角色。
-
处理类(Handler):可以是一个接口,用于接收请求并将请求分派到处理程序链条中(实际上就是一个数组链表),其中,会先将链中的第一个处理程序放入开头来处理。
-
具体处理类(HandlerA、B、C):按照链条顺序对请求进行具体处理。
接下来我们用实际场景来演示下代码
代码展示
我用我们公司在钉钉提交请假申请的场景来演示下代码
我们可以看到抄送人经过同意之后,会提交给直接主管,接着会给人力专员
//请假实体
@Builder
public class LeaveRequest {
//天数
private int leaveDays;
//姓名
private String name;
//请假事由
private String reason;
}
//请假责任链抽象处理类
public class AbstractLeaveHandler {
//领导名称
protected String handlerName;
//下一个处理节点(即更高级别的领导)
protected AbstractLeaveHandler nextHandler;
//设置下一节点
protected void setNextHandler(AbstractLeaveHandler handler){
this.nextHandler = handler;
}
//处理请假的请求,子类实现
protected void handlerRequest(LeaveRequest request){
}
}
抄送人(一般是人事部)
//抄送人接收
public class CCLeaveHandler extends AbstractLeaveHandler{
public CCLeaveHandler(String name) {
this.handlerName = name;
}
@Override
protected void handlerRequest(LeaveRequest request) {
//超过10天 不准假
if(request.getLeaveDays() > 10){
System.out.println("抄送人:" + handlerName + ",已经处理;流程结束。");
return;
}
if(null != this.nextHandler){
//审批,传送给下一个责任链
this.nextHandler.handlerRequest(request);
}else{
System.out.println("拒绝!");
}
}
}
直接主管类(部门直接领导)
//直接主管
public class DirectLeaderLeaveHandler extends AbstractLeaveHandler{
public DirectLeaderLeaveHandler(String name) {
this.handlerName = name;
}
@Override
protected void handlerRequest(LeaveRequest request) {
System.out.println("直接领导:" + handlerName + ",开始处理请假。");
if(null != this.nextHandler){
//审批,传送给下一个责任链
this.nextHandler.handlerRequest(request);
}else{
System.out.println("拒绝!");
}
}
}
人力专员
//hr
public class HRLeaveHandler extends AbstractLeaveHandler{
public HRLeaveHandler(String name) {
this.handlerName = name;
}
@Override
protected void handlerRequest(LeaveRequest request) {
System.out.println("人力专员:" + handlerName + ",已经处理;流程结束。");
if(null != this.nextHandler){
//审批
this.nextHandler.handlerRequest(request);
}else{
System.out.println("执行结束!");
}
}
}
public class DingDingTest {
public static void main(String[] args) {
LeaveRequest request = LeaveRequest.builder().leaveDays(20).name("小明").build();
CCLeaveHandler cc = new CCLeaveHandler("抄送人小李");
DirectLeaderLeaveHandler directLeaderLeaveHandler = new DirectLeaderLeaveHandler("直接领导,王总");
HRLeaveHandler hrLeaveHandler = new HRLeaveHandler("人力专员,小郭");
cc.setNextHandler(deptManagerLeaveHandler);
directLeaderLeaveHandler.setNextHandler(gManagerLeaveHandler);
hrLeaveHandler.handlerRequest(request);
}
}
从这段代码实现可以看出,责任链模式的实现非常简单,每一个具体的处理类都会保存在它之后的下一个处理类。当处理完成后,就会调用设置好的下一个处理类,直到最后一个处理类不再设置下一个处理类,这时处理链条全部完成。
责任链模式就像工厂的流水线作业一样,按照某一个标准化的流程来执行,用于规则过滤、Web 请求协议解析等具备链条式的场景中,通过拆分不同的处理节点来完成整个流程的处理。
责任链模式在实际代码中也是应用比较广泛的。且容易理解的。
OK 今天的代码部分就到这里,我们总结下
总结
为什么使用责任链模式?
-
第一个,解耦使用者和后台庞大的流程化处理
-
第二个,为了动态更换流程处理中的处理对象。比如,在请假流程中,申请人一般会提交申请给直接领导审批,但有时直接领导可能无法进行审批操作,这时系统就可以更换审批人到其他审批人,这样就不会阻塞请假流程的审批。
优点嘛,我个人认为 1、增强了具体处理类的职责独立性
2、这避免了使用众多的 if 或者 if···else 语句。简化了对象之间前后关联处理的复杂性。每个对象只需存储一个指向后继者的引用,不需保持其他所有处理者的引用,
缺点还是有的,这样的话,类可能会增多。第二,调试难度增大,出现问题,调试起来不好调试。第三,也会在一定程度上影响性能。
netty当中的责任链
这里稍微提下,牛逼框架Netty当中也有用到责任链。大家下去可以了解下,这里后面将netty会讲下
Netty中的ChannelPipeline责任链: pipeline管道保存了通道所有处理器信息,创建channel时自动创建一个专有的pipeline,入站事件和出站事件会调用pipeline上的处理器
线外知音
感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。
我已经将本章收录在专题里,点击下方专题,关注专栏,我会每天发表干货,本月我会持续输入设计模式。
加油! 我们下期再见!