设计模式之职责链

职责链(Chain of Responsibility)模式属于23种设计模式之一,职责链也称为责任链,《Design pattern: the basis of reusable object-oriented software》(以下简称DP)一书中是这样描述职责链的:职责链模式使多个对象都有机会处理请求,从而避免请求发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿这条链传递该请求,直到有一个对象处理它为止。

DP中对职责链模式的定义稍微不是那么的好理解,简单来说就是将能够处理用户请求的对象都串成一条链,然后将用户的请求放进这条链里,这个请求就可以在链中的对象之间传递,一直传递到能够处理它的对象上为止。

可能这么说还不太好理解,我们可以举个生活中的例子,例如员工申请加薪。我们都知道普通员工想要申请加薪,首先需要将加薪的申请书提交给主管,如果主管没有权限处理这个加薪的事情,那么主管就会将申请提交到部门经理那边,由部门经理去处理。如果部门经理也没有权处理的话,就会将申请再提交到总经理或人力资源总监手上,总经理说我可以处理,那么这个加薪申请就可以被处理了。而普通员工并不知道他提交的这个加薪申请被谁处理了,也不知道处理的经过,他只需要知道将申请提交给主管,最后等结果即可。这就是一个典型的职责链机制:客户端发送请求到职责链的链头上,然后这个请求就会在链中的对象之间逐个传递,直到被某个对象处理并返回结果给客户端为止。

示意图:

不使用职责连模式设计的代码:

就拿以上所说到的例子,我们来用代码做一个简单的试验,先不使用职责链模式,就用最简单方式去实现这个场景。

1.编写一个RaisesRequest类,用来封装请求内容:

package org.zero01.test;

public class RaisesRequest {

    public String getRequestName() {
        return requestName;
    }

    public void setRequestName(String requestName) {
        this.requestName = requestName;
    }

    public int getRequestNumber() {
        return requestNumber;
    }

    public void setRequestNumber(int requestNumber) {
        this.requestNumber = requestNumber;
    }

    private String requestName;
    private int requestNumber;

}

2.编写管理者类Manager,这个类用于处理用户的请求:

package org.zero01.test;

import org.zero01.test.RaisesRequest;

public class Manager {

    // 返回处理结果
    public void getResult(String position, RaisesRequest raisesRequest) {

        if (position.equals("主管")) {

            if (raisesRequest.getRequestName().equals("加薪")) {
                System.out.println("主管:我无权处理");
            } else {
                System.out.println("主管:你在说啥");
            }

        } else if (position.equals("部门经理")) {

            if (raisesRequest.getRequestName().equals("加薪")) {
                System.out.println("部门经理:我无权处理");
            } else {
                System.out.println("部门经理:你在说啥");
            }

        } else if (position.equals("人力资源总监")) {

            if (raisesRequest.getRequestName().equals("加薪")) {
                System.out.println("人力资源总监:我无权处理");
            } else {
                System.out.println("人力资源总监:你在说啥");
            }

        } else if (position.equals("总经理")) {

            if (raisesRequest.getRequestName().equals("加薪") && raisesRequest.getRequestNumber() <= 1000) {
                System.out.println("总经理:ok,批准了");
            } else if(raisesRequest.getRequestName().equals("加薪") && raisesRequest.getRequestNumber() > 1000){
                System.out.println("总经理:emmm我考虑一下");
            }else{
                System.out.println("总经理:你在说啥");
            }

        } else {
            System.out.println("没有这个职位");
        }
    }
}

3.最后编写客户端类Client:

package org.zero01.test;

public class Client {

    public static void main(String[] args) {

        // 封装请求内容
        RaisesRequest raisesRequest = new RaisesRequest();
        raisesRequest.setRequestName("加薪");
        raisesRequest.setRequestNumber(1000);

        // 发送给不同的管理者
        Manager manager = new Manager();
        manager.getResult("主管", raisesRequest);
        manager.getResult("部门经理", raisesRequest);
        manager.getResult("人力资源总监", raisesRequest);
        manager.getResult("总经理", raisesRequest);

    }
}

运行结果:

主管:我无权处理
部门经理:我无权处理
人力资源总监:我无权处理
总经理:ok,批准了

ok,从运行结果也可以看到,这样的代码也是勉勉强强实现了我们的需求。但是,很直观的可以看到代码是有多糟糕,Manager类里的if else全都集中在一个方法里,造成一个方法里重复的代码太多。而且不同部门的管理者都在这个方法里,这就违反了单一职责原则,如果我要增加一个部门的管理者或减少一个部门的管理者,都需要去修改这个类里的代码以及客户端的代码,违反了开-闭原则。这样的代码耦合性是相当高的,但是我们要怎么样对这些代码进行解耦呢?那么这时候就需要使用到职责链模式了。

职责链模式结构图:

职责连模式示例代码:
1.Handler类,定义一个处理请求的接口:

package org.zero01.test;

public abstract class Handler {

    protected Handler successor;

    // 设置继任者
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handlerRequest(int request);

}

2.ConcreteHandler1类,是一个具体的处理类,它只能处理它所负责的请求,不能处理的就传递给它的后继者处理:

package org.zero01.test;

public class ConcreteHandler1 extends Handler {

    public void handlerRequest(int request) {
        // 处理0-10之间的请求
        if (request >= 0 && request <= 10) {
            System.out.println("ConcreteHandler1处理请求" + request);
        } else if (successor != null) {
            // 将请求传递到下一位
            successor.handlerRequest(request);
        }
    }
}

3.ConcreteHandler2:

package org.zero01.test;

public class ConcreteHandler2 extends Handler {

    public void handlerRequest(int request) {
        // 处理10-20之间的请求
        if (request >= 10 && request <= 20) {
            System.out.println("ConcreteHandler2处理请求" + request);
        } else if (successor != null) {
            // 将请求传递到下一位
            successor.handlerRequest(request);
        }
    }
}

4.ConcreteHandler3:

package org.zero01.test;

public class ConcreteHandler3 extends Handler {

    public void handlerRequest(int request) {
        // 处理20-30之间的请求
        if (request >= 20 && request <= 30) {
            System.out.println("ConcreteHandler3处理请求" + request);
        } else if (successor != null) {
            // 将请求传递到下一位
            successor.handlerRequest(request);
        }
    }
}

5.Client,客户端类,在该类中向职责链提交请求:

package org.zero01.test;

public class Client {

    public static void main(String[] args) {

        Handler h1 = new ConcreteHandler1();
        Handler h2 = new ConcreteHandler2();
        Handler h3 = new ConcreteHandler3();

        // 设置职责链的上家与下家,h1作为链头
        h1.setSuccessor(h2);
        h2.setSuccessor(h3);

        int[] numbers = {10, 20, 30, 51, 25, 5, 8, 7, 15, 47};

        for (int i : numbers) {
            h1.handlerRequest(i);
        }
    }
}

运行结果:

ConcreteHandler1处理请求10
ConcreteHandler2处理请求20
ConcreteHandler3处理请求30
ConcreteHandler3处理请求25
ConcreteHandler1处理请求5
ConcreteHandler1处理请求8
ConcreteHandler1处理请求7
ConcreteHandler2处理请求15

职责链的好处:

从以上这个小示例可以看到,每当我从客户端提交一个请求时,请求是沿着职责链传递的,直至传递到有对应的ConcreteHandler对象来处理它。请求的处理着与发送者都不需要知道对方的明确信息,且链中的对象自己也并不知道链的结构。所以职责链可以简化对象之间的互相连接,它们仅需要保持一个指向其后继者的引用,而不需要保持它所有的候选者的引用,从这点也可以看出职责链是单链的结构,这样大大的降低了类之间的耦合度,因为它们都只依赖于一个抽象父类。

类之间低耦合的好处就是可以随时增加、减少以及修改某个处理请求的结构代码,增强了给对象指派职责的灵活性。但是要注意一个请求可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。这时候估计就有人注意到以上代码的一个小细节,数值大于30的请求都没有被处理,这就是典型的请求被传递到了链的末端也得不到处理。所以在设计代码时还需要仔细考虑全面,如果是上面这个例子我们就可以简单的加一个else分支来处理这个问题,而不同的场景下需要根据实际情况使用相应的方式去处理。

使用职责连模式重构之前的代码:

我们顺便把需求更改一下,让不同的管理者可以处理不同额度的加薪请求。

代码结构图:

1.抽象一个Manager管理类:

package org.zero01.test;

public abstract class Manager {

    protected Manager superior;
    protected String position;

    // 设置管理对象的名称
    public Manager(String position) {
        this.position = position;
    }

    // 设置上级对象
    public void setSuperior(Manager superior) {
        this.superior = superior;
    }

    // 处理加薪请求的方法
    public abstract void raisesRequest(String requestName,int requestNumber);

}

2.编写主管类,这是具体的处理类,可以处理100元以内的加薪请求:

package org.zero01.test;

public class Director extends Manager {

    public Director(String position) {
        super(position);
    }

    public void raisesRequest(String requestName, int requestNumber) {

        // 有权处理100元以内的加薪
        if (requestName.equals("加薪") && requestNumber <= 100) {
            System.out.println(position + ":ok,批准了");
        } else if (superior != null) {
            // 将请求传递给上级
            superior.raisesRequest(requestName, requestNumber);
        }

    }
}

3.部门经理类,可以处理300元以内的加薪请求:

package org.zero01.test;

public class BranchManager extends Manager{

    public BranchManager(String position) {
        super(position);
    }

    public void raisesRequest(String requestName, int requestNumber) {

        // 有权处理300元以内的加薪
        if (requestName.equals("加薪") && requestNumber <= 300) {
            System.out.println(position + ":ok,批准了");
        } else if (superior != null) {

            // 将请求传递给上级
            superior.raisesRequest(requestName, requestNumber);
        }
    }
}

4.人力资源总监类,可以处理600元以内的加薪请求:

package org.zero01.test;

public class CHO extends Manager{

    public CHO(String position) {
        super(position);
    }

    public void raisesRequest(String requestName, int requestNumber) {

        // 有权处理600元以内的加薪
        if (requestName.equals("加薪") && requestNumber <= 600) {
            System.out.println(position + ":ok,批准了");
        } else if (superior != null) {

            // 将请求传递给上级
            superior.raisesRequest(requestName, requestNumber);
        }
    }
}

5.总经理类,可以处理1000元以上的加薪请求:

package org.zero01.test;

public class GeneralManager extends Manager{

    public GeneralManager(String position) {
        super(position);
    }

    public void raisesRequest(String requestName, int requestNumber) {

        // 有权处理1000元以上的加薪
        if (requestName.equals("加薪") && requestNumber <= 1000) {
            System.out.println(position + ":ok,批准了");
        }else {
            // 1000元以上看心情
            System.out.println(position + ":emmm我考虑一下");
        }
    }
}

6.员工类,也就是客户端类:

package org.zero01.test;

public class Staff {

    public static void main(String[] args) {

        // 实例化各个管理者对象
        Manager director = new Director("主管");
        Manager branchManager = new BranchManager("部门经理");
        Manager cho = new CHO("人力资源总监");
        Manager generalManager = new GeneralManager("总经理");

        // 设置上级与下级
        director.setSuperior(branchManager);
        branchManager.setSuperior(cho);
        cho.setSuperior(generalManager);

        director.raisesRequest("加薪",100);
        director.raisesRequest("加薪",300);
        director.raisesRequest("加薪",600);
        director.raisesRequest("加薪",1000);
        director.raisesRequest("加薪",1500);

    }
}

运行结果:

主管:ok,批准了
部门经理:ok,批准了
人力资源总监:ok,批准了
总经理:ok,批准了
总经理:emmm我考虑一下

使用职责链模式来重构之前的代码后,就很好的解决了原来大量的分支判断耦合在一起,造成维护困难、灵活性差且不好扩展的问题。

原文地址:http://blog.51cto.com/zero01/2065240

时间: 2024-10-12 00:42:28

设计模式之职责链的相关文章

设计模式之职责链模式(JAVA实现)

学习netty框架时,看到有人说netty用到了设计模式的职责链模式,学习一下职责链模式,主要参考大话设计模式. 主要场景: 小菜想要加薪,向经理提出加薪请求,经理没有权限,经理交由总监处理,总监也没有权限,交由总经理处理,最后,总经理处理了,不同意. 职责链的意思就是,如果没有处理该类请求的权限,交由具有更高权限的对象处理.依次类推 这里将处理对象抽象为Handler类,经理.总监等为继承Handler的具体处理类,同时模拟客户端Client向Handler对象发出请求 类图如下 下面为具体代

C++设计模式实现--职责链(Chain of Responsibility)模式

一. 概述 职责链模式: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 二. 举个例子 员工要求加薪 公司的管理者一共有三级:总经理.总监.经理,如果一个员工要求加薪,应该向主管的经理申请,如果加薪的数量在经理的职权内,那么经理可以直接批准,否则将申请上交给总监.总监的处理方式也一样,总经理可以处理所有请求.这就是典型的职责链模式,请求的处理形成了一条链,直到有一个对象处理请求. 结构图如下: 假

图解Java设计模式之职责链模式

图解Java设计模式之职责链模式 学校OA系统的采购审批项目 :需求是 传统方案解决OA系统审批,传统的设计方案 职责链模式基本介绍 职责链模式解决OA系统采购审批 职责链模式在SpringMVC框架应用的源码 职责链模式的注意事项和细节 学校OA系统的采购审批项目 :需求是 采购员采购教学器材1)如果金额 小于等于 5000,由教学主任审批 (0<=x<=5000)2)如果金额 小于等于 10000,由院长审批(5000 < x <= 10000)3)如果金额 小于等于 3000

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

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化托付给还有一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些详细的类的信息封装起来.第二,它们隐藏了这些类的实例是怎样被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,

深入理解JavaScript系列(38):设计模式之职责链模式

介绍 职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. 也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者.提交请求的对象并不明确知道哪一个对象将会处理它——也就是该请求有一个隐式的接受者(implicit receiver).根据运行时刻,任一候选者都可以响应相应的请求,候选者的数目是任意

java设计模式之职责链模式

[学习难度:★★★☆☆,使用频率:★★☆☆☆] "一对二","过","过"--这声音熟悉吗?你会想到什么?对!纸牌.在类似"斗地主"这样的纸牌游戏中,某人出牌给他的下家,下家看看手中的牌,如果要不起上家的牌则将出牌请求再转发给他的下家,其下家再进行判断.一个循环下来,如果其他人都要不起该牌,则最初的出牌者可以打出新的牌.在这个过程中,牌作为一个请求沿着一条链在传递,每一位纸牌的玩家都可以处理该请求.在设计模式中,我们也有一种专

Java设计模式之职责链设计模式

1.什么是-职责链设计模式 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任.Tomcat中的Filter就是使用了责任链模式,创建一个Filter除了要在web.xml文件中做相应配置外,还需要实现javax.servlet.Filter接口. 2.职责链设计模式

设计模式值职责链模式(行为型)

目录 一.行为型模式 二.职责链模式定义 三.职责链模式角色 四.简单实例 五.模式应用 一.行为型模式 介绍职责链模式之前先介绍一下行为型设计模式,因为按照GoF模式分类,职责链就是一种行为型设计模式.行为型设计模式就是主要表示类或者对象之间的关联关系,分为类行为型和对象行为型.类行为型一般都是通过类的继承或者多态等等方式实现.对象行为型就是通过对象的聚合等等关联实现. 二.职责链模式定义 职责链模式是一种对象行为型模式.根据"合成复用"原则,尽量使用关联来取代类继承,对象行为型可以

设计模式之职责链模式

职责链模式 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合.将系统连成一条线,并沿着这条线传递请求,直到有一个对象处理他为止. Handler package com.hml.responsiblity; public abstract class Handler { protected Handler successor; public Handler getSuccessor() { return successor; } public void setSuccesso