责任链模式

一 定义

责任链模式是行为型设计模式之一。所谓链,是指多个节点首尾相连所构成的模式。对于链式结构,每个节点都可以被拆来再连接,因此链式结构有很好的灵活性。应用到编程领域,将每个节点看做是一个对象,每个对象拥有不同的处理逻辑,将一个请求从链式的首端出发,沿着链式的路径依次传递给每一个节点对象,直至对象处理这个请求为止。

定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

二 模式结构

角色介绍

  • Handler:抽象处理角色,声明一个请求处理的方法,并在其中保持一个对下一个处理节点Handler对象的引用。
  • ConcreteHandler:具体的处理角色,对请求进行处理,如果不能进行处理,就将请求发送给下一个节点的处理对象。

三 通用代码

下面是一个责任链模式简化版的模式代码。

  • 抽象处理者
/*
 * 抽象处理者
 * @author Jackson
 * @version 1.0.0
 * since 2019 04 23
 */
public abstract class Handler {

    protected Handler successor; // 下一个节点的处理者

    /**
     * 请求处理
     * @param condition  请求条件
     */
    public abstract void handleRequest(String condition);
}
  • 具体的处理者1
public class ConcreteHandler1 extends Handler{

    @Override
    public void handleRequest(String condition) {
        if (condition.equals("ConcreteHandler1")){
            System.out.println("ConcreteHandler1 handled");
            return;
        }else {
            successor.handleRequest(condition);
        }
    }
}
  • 具体的处理者2
public class ConcreteHandler2 extends Handler{

    @Override
    public void handleRequest(String condition) {
        if (condition.equals("ConcreteHandler2")){
            System.out.println("ConcreteHandler2 handled");
            return;
        }else {
            successor.handleRequest(condition);
        }
    }
}
  • 测试代码

        // 构造一个ConcreteHandler1对象
        ConcreteHandler1 handler1=new ConcreteHandler1();

        // 构造一个ConcreteHandler2对象
        ConcreteHandler2 handler2=new ConcreteHandler2();

         // 设置handler1的下一个节点
        handler1.successor=handler2;

        // 设置handler2的下一个节点
        handler2.successor=handler1;

        // 处理请求
        handler1.handleRequest("ConcreteHandler1");

运行结果不贴图了,测试代码是交给ConcreteHandler1处理。

上面是一个简化版的通用代码模式,因为对于请求来说,形式是固定的,是一个字符串,判断一个节点是否能处理该请求,是看该字符串是否和条件匹配。然而在大多数情况下,责任链的请求和对应的处理规则不尽相同,在这种情况下,可以将请求进行封装,同时对请求的规则进行封装。


模式代码如下:

  • 抽象请求者
public abstract class AbstractRequest {

    private Object obj;

    public AbstractRequest(Object obj) {
        this.obj = obj;
    }

    /**
     * 获取处理的内容对象
     * @return
     */
    public Object getContent(){
        return obj;
    }

    /**
     * 获取请求级别
     * @return
     */
    public abstract int getRequestLevel();
}
  • 抽象处理者
public abstract class AbstractHandler {

    protected AbstractHandler nexthandler;  // 下一节点上的处理者对象

    public final void handleRequest(AbstractRequest request){
        // 判断当前处理者对象的处理级别是否与请求者的级别一致
        if (getHandleLevel()==request.getRequestLevel()){
            // 一致则由该处理对象处理
            handle(request);
        }else {
            // 否则将该请求对象转发给下一个节点上的请求对象
            if (nexthandler!=null){
                nexthandler.handle(request);
            }else {
                // 当前所有处理者对象均不能处理该请求时输出
                System.out.println("All of handler can  not handle the request!");
            }
        }

    }


    /**
     * 获取处理者对象的处理级别
     * @return
     */
    protected abstract int getHandleLevel();


    /**
     * 每个处理者对象的具体处理方式
     * @param request
     */
    protected abstract void handle(AbstractRequest request);
    
}
  • 具体请求者
public class Request1 extends AbstractRequest{

    public Request1(Object obj) {
        super(obj);
    }

    @Override
    public int getRequestLevel() {
        return 1;
    }
}

public class Request2 extends AbstractRequest{

    public Request2(Object obj) {
        super(obj);
    }

    @Override
    public int getRequestLevel() {
        return 2;
    }
}

public class Request3 extends AbstractRequest{

    public Request3(Object obj) {
        super(obj);
    }

    @Override
    public int getRequestLevel() {
        return 3;
    }
}

  • 具体处理者
public class Handler1 extends AbstractHandler{

    @Override
    protected int getHandleLevel() {
        return 1;
    }

    @Override
    protected void handle(AbstractRequest request) {
        System.out.println("Handler1 handle request:"+request.getRequestLevel());
    }
}

public class Handler2 extends AbstractHandler{

    @Override
    protected int getHandleLevel() {
        return 2;
    }

    @Override
    protected void handle(AbstractRequest request) {
        System.out.println("Handler2 handle request:"+request.getRequestLevel());
    }
}

public class Handler3 extends AbstractHandler{

    @Override
    protected int getHandleLevel() {
        return 3;
    }

    @Override
    protected void handle(AbstractRequest request) {
        System.out.println("Handler3 handle request:"+request.getRequestLevel());
    }
}
  • 测试代码
 // 构造三个处理对象
        AbstractHandler handler11=new Handler1();
        AbstractHandler handler12=new Handler2();
        AbstractHandler handler13=new Handler3();
        // 设置当前处理对象的下一个节点的处理者对象
        handler11.nexthandler=handler12;
        handler12.nexthandler=handler13;
        // 构造三个请求对象
        AbstractRequest request1=new Request1("Request1");
        AbstractRequest request2=new Request2("Request2");
        AbstractRequest request3=new Request3("Request3");

        // 从链式的首端发起请求
        handler11.handleRequest(request1);
        handler11.handleRequest(request2);
        handler11.handleRequest(request3);
  • 运行结果


我们从链式的首端开始处理请求,当请求时request1时,handler11就可以处理,当请求时request2时,handler11就不能处理了,知道handler12才能处理,以此类推。

四 实例

下面举一个具体的实例,以公司走合同为例,小民要签一个合同,总价10w,小民向组领导提交申请,组领导一看,我的权限只能批准2w内的合同,就往上提交给了部门负责人,部门负责人一看,总额不小啊,我只能批准5w以内的合同,然后提交给了公司领导,公司领导就有权限批准了。就这样层层往上传达,直到遇到有权限处理的人。具体代码如下:

  • 抽象领导类
    在这个抽象类中主要做了两件事,一是定义了两个抽象方法来确定领导应有的行为和属性,而是声明了一个处理合同请求的方法来确定当前领导是否有能力处理合同。如果没有处理权限,就将请求转发给上级领导处理,知道遇到有能力处理的领导。
public abstract class Leader {

    protected Leader nextHandler;  // 上级领导处理者

    /**
     * 处理合同
     * @param money
     */
    public void handleRequest(int money){
        if (money<=getLimit()){
            handle(money);
        }else {
            if (nextHandler!=null){
                nextHandler.handleRequest(money);
            }
        }
    }


    /**
     * 自身能批复的额度权限
     * @return
     */
    protected abstract int getLimit();

    /**
     * 处理合同行为
     * @param money
     */
    protected abstract void handle(int money);
}
  • 具体的领导
public class GroupLeader extends Leader{

    @Override
    protected int getLimit() {
        return 20000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("组领导审批合同金额:"+money);
    }
}

public class DepartmnetLeader extends Leader{
    @Override
    protected int getLimit() {
        return 50000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("部门领导审批合同金额:"+money);
    }
}


public class CompanyLeader extends Leader{
    @Override
    protected int getLimit() {
        return 100000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("公司领导审批合同金额:"+money);
    }
}
  • 测试代码
// 构建各个领导
        Leader groupLeader=new GroupLeader();
        Leader departmentLeader=new DepartmnetLeader();
        Leader companyLeader=new CompanyLeader();
        // 设置上一级领导处理者
        groupLeader.nextHandler=departmentLeader;
        departmentLeader.nextHandler=companyLeader;

        // 发起合同申请
        groupLeader.handleRequest(10000);
        groupLeader.handleRequest(30000);
        groupLeader.handleRequest(80000);
  • 运行结果



    可以看到,不同领导处理的权限是不同的。

五 优缺点

优点:请求者和处理者解耦合,请求者可以不用知道是谁处理的,处理者也可以不知道请求者,提高了代码的灵活性。
缺点:性能问题,每个请求都从链的开端遍历到链尾,如果链比较长时,性能将会是一个很大的问题。

六 使用场景

  • 多个对象可以处理同一请求,但具体哪个对象处理则在运行时决定。
  • 在请求处理者不明确的情况下想多个对象提交请求。
  • 需要动态指定一组对象处理请求。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容