一、责任链模式介绍

责任链模式:将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递。从而避免请求的

发送者和接受者之间的耦合关系。链上的对象逐个判断是否有能力处理该请求,如果能则就处理,如果不能,则传给链上的下一个对象。

直到有一个对象处理它为止。

场景:

1、打牌时,轮流出牌

2、接力赛跑

3、请假审批

4、公文审批

责任链UML图:

Handler:表示处理请求的接口,在这个接口里可以定义链上的下一个继承者,和一个处理请求的抽象方法。

ConcreteHandler1和ConcreteHandler2:表示具体的处理者

二、责任链模式代码实现

这里以请假的流程为例,用责任链模式来实现

首先这里定义一个请假信息的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * 请假的基本信息
 */
public class LeaveRequest {
    private String empName;//请假人
    private int leaveDays;//请假天数
    private String reason;//请假理由   
    public LeaveRequest(String empName, int leaveDays, String reason) {
        super();
        this.empName = empName;
        this.leaveDays = leaveDays;
        this.reason = reason;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public int getLeaveDays() {
        return leaveDays;
    }
    public void setLeaveDays(int leaveDays) {
        this.leaveDays = leaveDays;
    }
    public String getReason() {
        return reason;
    }
    public void setReason(String reason) {
        this.reason = reason;
    }  
}

然后定义一个抽象类,来处理各个请求之间的关系。也就是UML图中的Handler部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 抽象类:管理责任链上的对象处理的抽象类
 */
public abstract class Leader {
    protected String name;
    protected Leader nextLeader;//下一个继承者
    public Leader(String name) {
        super();
        this.name = name;
    }
    //设置责任链上的下一个继承者
    public void setNextLeader(Leader nextLeader) {
        this.nextLeader = nextLeader;
    }
    //处理请求的抽象方法
    public abstract void handleRequest(LeaveRequest leader);
}

接下来就可以开始定义处理请求的具体对象了,比如处理请假信息的:主任,经理,总经理等等。这些对象都必须继承抽象类,来处理请求。

主任对象:处理小于等于3天的假期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//主任
public class Director extends Leader {
    public Director(String name) {
        super(name);
    }
    /**
     * 责任链上对象对请求的具体处理
     */
    @Override
    public void handleRequest(LeaveRequest leader) {
        if (leader.getLeaveDays()<=3) {
            System.out.println("请假人:"+leader.getEmpName()+",天数:"+leader.getLeaveDays()+",理由:"+leader.getReason());
            System.out.println("审批人:"+this.name+" 主任,审批通过!");
        }else{
            if (this.nextLeader != null ) {//如果有下一个继承者
                //让下一个继承者处理请求
                this.nextLeader.handleRequest(leader);
            }
        }
    }
}

经理对象:处理大于3天,小于等于10天的假期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//经理
public class Manager extends Leader {
    public Manager(String name) {
        super(name);
    }
    /**
     * 责任链上对象对请求的具体处理
     */
    @Override
    public void handleRequest(LeaveRequest leader) {
        if (leader.getLeaveDays()<=10) {
            System.out.println("请假人:"+leader.getEmpName()+",天数:"+leader.getLeaveDays()+",理由:"+leader.getReason());
            System.out.println("审批人:"+this.name+" 经理,审批通过!");
        }else{
            if (this.nextLeader != null ) {//如果有下一个继承者
                //让下一个继承者处理请求
                this.nextLeader.handleRequest(leader);
            }
        }
    }
}

总经理对象:处理大于等于10天,小于30天的请假信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//总经理
public class GeneralManager extends Leader {
    public GeneralManager(String name) {
        super(name);
    }
    /**
     * 责任链上对象对请求的具体处理
     */
    @Override
    public void handleRequest(LeaveRequest leader) {
        if (leader.getLeaveDays()<=30) {
            System.out.println("请假人:"+leader.getEmpName()+",天数:"+leader.getLeaveDays()+",理由:"+leader.getReason());
            System.out.println("审批人:"+this.name+" 总经理,审批通过!");
        }else{
//          if (this.nextLeader != null ) {//如果有下一个继承者
//              //让下一个继承者处理请求
//              this.nextLeader.handleRequest(leader);
//          }
            //总经理上面没人了,所以不往下发送请求。
            System.out.println("请假申请,最终不通过!最终审批人:"+this.name+"  总经理");
        }
    }
}

重要代码都写完了,下面开始测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
    //构建各个领导人
    Leader a = new Director("张三");//主任
    Leader b = new Manager("李四");//经理
    Leader c = new GeneralManager("王五");//总经理
    //设置各个责任链上的关系
    a.setNextLeader(b);//主任的下一个审批人为经理
    b.setNextLeader(c);//经理的下一个审批人为总经理
      
    //开始请假
    LeaveRequest request = new LeaveRequest("小明", 3, "旅游");
    a.handleRequest(request);//小明提交了请假申请给主任
}

控制台则打印:主任审批

请假人:小明,天数:3,理由:旅游

审批人:张三 主任,审批通过!

如果改成13天:则就是总经理审批

请假人:小明,天数:13,理由:旅游

审批人:王五 总经理,审批通过!

此时,我们发现,责任链上漏掉了副总经理,那也很好办。直接加上副总经理就行了

增加一个副总经理的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.fz.chainOfResponsibility;
 
/**
 * 副总经理
 */
public class ViceGeneralManager extends Leader {
    public ViceGeneralManager(String name) {
        super(name);
    }
    /**
     * 责任链上对象对请求的具体处理
     */
    @Override
    public void handleRequest(LeaveRequest leader) {
        if (leader.getLeaveDays()<=20) {
            System.out.println("请假人:"+leader.getEmpName()+",天数:"+leader.getLeaveDays()+",理由:"+leader.getReason());
            System.out.println("审批人:"+this.name+" 副总经理,审批通过!");
        }else{
            if (this.nextLeader != null ) {//如果有下一个继承者
                //让下一个继承者处理请求
                this.nextLeader.handleRequest(leader);
            }
        }
    }
}

测试的代码呢,构造副总经理对象。然后再设置继承者的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
    //构建各个领导人
    Leader a = new Director("张三");//主任
    Leader b = new Manager("李四");//经理
    //增加副总经理
    Leader b2 = new ViceGeneralManager("赵四");//副总经理
    Leader c = new GeneralManager("王五");//总经理
    //设置各个责任链上的关系
    a.setNextLeader(b);//主任的下一个审批人为经理
    b.setNextLeader(b2);//经理的下一个审批人为副总经理
    b2.setNextLeader(c);//副总经理的下一个审批人为总经理
    //开始请假
    LeaveRequest request = new LeaveRequest("小明", 19, "旅游");
    a.handleRequest(request);//小明提交了请假申请给主任
}

测试结果就是:副总经理审批

请假人:小明,天数:19,理由:旅游

审批人:赵四 副总经理,审批通过!

三、责任链模式总结

实现方式:

1、链表方式:比如刚才的请假审批

2、非链表方式:通过集合,数组生成责任链更加实用,将链表上的各个对象都添加到集合中,然后通过反射给构建出来。

然后在容器里一个个的处理。(也就是说把测试代码中除了请假的其他代码都给用一个类来处理)

开发中常见场景:

1、Java的异常机制就是一个责任链模式,一个try可以对应多个cathc。如果某一个catch不匹配,则跳到下一个catch中

2、JavaScript语言中的事件的冒泡和捕获机制

3、Servlet开发中,过滤器的链式处理

4、Struts2中,拦截器的调用也是典型的责任链模式

责任链的好处:

​1、接受者和发送者都没有对方的明确信息,且链中的对象也并不知道链的结构,结果是责任链可简化对象的相互连接,它们仅需保持一个指向其

后继者的引用,而不需要保持它所有的候选继承者,大大的降低了耦合度。

请求者不用管具体哪个对象会处理,反正该请求肯定会被处理就行了

2、可以随时增加或者修改处理一个请求的结构,增加了给对象指派职责的灵活性

Java23种设计模式学习笔记【目录总贴】

参考资料:

  大话设计模式(带目录完整版).pdf

  HEAD_FIRST设计模式(中文版).pdf

  尚学堂_高淇_java300集最全视频教程_【GOF23设计模式】

职责链模式(Chain of Responsibility)的更多相关文章

  1. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  2. 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就 ...

  3. 职责链模式(Chain of Responsibility)(对象行为型)

    1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就推卸给另外个一个部门(对象).至于到底谁来解决这个问题呢?政府部门就是为了可以避免屁民的请求与 ...

  4. 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

    责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...

  5. 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...

  6. 设计模式之职责链模式(Chain of Responsibility)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  7. 行为型设计模式之职责链模式(Chain of Responsibility)

    结构 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 适用性 有多个的对象可以处理一个请求,哪个 ...

  8. 职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

  9. 职责链模式(chain of responsibility Pattern)

    职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. •Handler: 抽象处理者:定义出一个 ...

  10. C#设计模式——职责链模式(Chain Of Responsibility Pattern)

    一.概述 在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使 ...

随机推荐

  1. linux命令——chmod/chown

    改变文件所有权chown 例如 sudo chown username myfile 1 myfile文件的所有权变为username. chown -R username /files/work 1 ...

  2. 《Java入门第三季》第二章 认识 Java 中的字符串

    什么是 Java 中的字符串.1.在Java的世界里,字符串被作为String类型的对象处理. 2.通用的初始化的方式:String s = new String("i love you & ...

  3. 寻路算法A*, JPS(跳点搜索)的一些杂谈

    A*是一个比较经典的启发式寻路算法.是基于dijkstra算法,但是加入了启发函数,使路径搜索效率更高.实现起来很简单.不过要做到通用性高,比如支持各种不同类型的地图,甚至不仅仅是地图,而是个图结构如 ...

  4. asp.net操作GridView添删改查的两种方法 及 光棒效果

    这部份小内容很想写下来了,因为是基础中的基础,但是近来用的比较少,又温习了一篇,发现有点陌生了,所以,还是写一下吧. 方法一:使用Gridview本身自带的事件处理,代码如下(注意:每次操作完都得重新 ...

  5. Vue 组件间传值

    前言 Vue 作为现在比较火的框架之一,相信您在使用的过程中,也会遇到组件间传值的情况,本文将讲解几种 Vue 组件间传值的几种方法,跟着小编一起来学习一下吧! 实现 注意: 学习本文,需要您对 Vu ...

  6. Codeforces679E. Bear and Bad Powers of 42

    传送门 今天子帧的一套模拟题的T3. 考试的时候其实已经想到了正解了,但是一些地方没有想清楚,就没敢写,只打了个暴力. 首先考虑用线段树维护区间信息. 先把每个值拆成两个信息,一是距离他最近的且大于他 ...

  7. 编解码技术:I帧与IDR帧的区别总结

    编解码技术:I帧与IDR帧的区别总结 DR(Instantaneous Decoding Refresh)--即时解码刷新. I帧与IDR帧的相同点在于: 1.I和IDR帧都是使用帧内预测的: 2.都 ...

  8. java计算两个日期之间相隔的月份(向下取整)

    最近需求里面有个需要计算两个日期之间相隔的月份,写起来还挺繁琐,需要将各种情况都要考虑到,写了一个作为以后自己的工具吧. //获取哪一天 public static int getDay(Date d ...

  9. Vue中使用百度地图——设置地图标注

    知识点:创建Map实例,为指定的位置设置标注 参考博客:https://www.cnblogs.com/liuswi/p/3994757.html 1.效果图:初始化地图,设置指定经纬度为地图中心点坐 ...

  10. Nodejs Q promise设计思路

    Nodejs Q promise库 前言 Q库为nodejs提供了一个基于promise的编程方式,从此避免了一层又一层的callback调用.不过Q的灵活性也给我造成了很大困扰,我可以用promis ...