责任链模式

引言

如果在学校,我们想提交一张表,但是表上有领导签字部分,可以辅导员签字、学院领导签字、校级领导签字、校长签字等等,这张表按照这条签字链一级一级的向上级传递,直到有一个领导签了字为止,像这种链式的处理模式就是责任链模式。

1.概念

责任链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。责任链模式是一种对象行为型模式。

2.模式结构

3.模式分析

Handler:抽象处理者,定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。核心代码如下:

java 复制代码
public abstract class Handler {

    protected Handler successor;//维持对下家的引用

    public void setSuccessor(Handler successor) {

        this.successor = successor;

    }

    public abstract void handleRequest (String request);

}

ConcreteHandler:具体处理者,它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者。在具体处理者中可以访问链中下一个对象,以便请求的转发。核心代码如下:

java 复制代码
class ConcreteHandler extends Handler{

    public void handleRequest(String request){

        if(请求满足条件) {

            //处理请求

        }else{

            this.successor.handleRequest(request);//转发请求

        }

    }

}

由于责任链模式链上的每个对象都有两种选择:处理请求或责任推给下家,因此又可以分为纯的责任链和不纯的责任链。

一个纯的责任链模式要求一个具体处理者对象只能在两个行为中选择一个:一个是承担责任,另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况,因此请求最终一定会被一个对象处理。

一个不纯的责任链模式里面,请求可以最终不被任何接收端对象所接收。

4.具体实例分析

ReimbursementRequest:财务报销请求类,定义了报销请求的格式,有金额和用途两个属性。具体代码如下:

java 复制代码
//财务报销请求

public class ReimbursementRequest {

    private double money;//金额

    private String purpose;//用途

    public ReimbursementRequest(double money, String purpose) {

        this.money = money;

        this.purpose = purpose;

    }

    public double getMoney() {

        return money;

    }

    public String getPurpose() {

        return purpose;

    }

}

ReimbursementHandler:抽象处理者,是一个抽象类,维护了一个对责任链中下家的引用,但类与类之间不知道各自的下家是什么。同时定义了设置下家的函数和抽象处理请求的方法。具体代码如下:

java 复制代码
//抽象处理类:报销者

public abstract class ReimbursementHandler {

    protected ReimbursementHandler successor;//维持对下家的引用


    public void setSuccessor(ReimbursementHandler successor) {

        this.successor = successor;

    }


    public abstract void handleRequest (ReimbursementRequest request);

}

ManagerHandler:具体处理者,表示经理,继承抽象处理者,同时实现了抽象处理方法,在方法中定义了处理和传递责任两种行为。具体代码如下:

java 复制代码
//具体处理类:经理

class ManagerHandler extends ReimbursementHandler{

    @Override

    public void handleRequest(ReimbursementRequest request){

        if(request.getMoney() <= 1000) {

            System.out.println("经理报销财务请求:" + request.getPurpose() + " 报销金额:" + request.getMoney());

        }else if(successor != null){

            this.successor.handleRequest(request);//转发请求

        }

    }

}

DepartmentHeadHandler:具体处理者,表示部门主管,报销额度比经理大,继承抽象处理者,同时实现了抽象处理方法,在方法中定义了处理和传递责任两种行为。具体代码如下:

java 复制代码
//具体处理类:部门主管

public class DepartmentHeadHandler extends ReimbursementHandler{

    @Override

    public void handleRequest(ReimbursementRequest request){

        if(request.getMoney() <= 10000) {

            System.out.println("部门主管报销财务请求:" + request.getPurpose() + " 报销金额:" + request.getMoney());

        }else if(successor != null){

            this.successor.handleRequest(request);//转发请求

        }

    }

}

FinanceHandler:具体处理者,表示财务部门,报销额度比部门主管大,继承抽象处理者,同时实现了抽象处理方法,在方法中无论金额大小,必须报销。****这种写法就是纯的责任链模式,因为无论其他对象是否处理报销请求,在财务部门一定会进行处理。而如果给财务部门的报销加上金额上限,比如<=100000元,那财务部门有可能就不会处理报销请求,进而系统中没有对象处理请求,这就成为不纯的责任链模型。****具体代码如下:

java 复制代码
//具体处理类:财务部门

public class FinanceHandler extends ReimbursementHandler{

    @Override

    public void handleRequest(ReimbursementRequest request){

        //纯的责任链:必须有一个对象处理财务报销

        System.out.println("财务部门报销财务请求:" + request.getPurpose() + " 报销金额:" + request.getMoney());

    }

}

Client:客户端,负责构建责任链,指定处理请求的顺序,在未构造责任链前,每个类都不知道自己的下家是谁。具体代码如下:

java 复制代码
public class Client {

    public static void main(String[] args) {

        //报销请求

        ReimbursementRequest request1 = new ReimbursementRequest(500,"员工住宿");

        ReimbursementRequest request2 = new ReimbursementRequest(5000,"团建活动");

        ReimbursementRequest request3 = new ReimbursementRequest(50000,"购买电脑5台");



        ReimbursementHandler manager = new ManagerHandler();

        ReimbursementHandler departmentHead = new DepartmentHeadHandler();

        ReimbursementHandler finance = new FinanceHandler();

        //客户端负责构建责任链

        manager.setSuccessor(departmentHead);

        departmentHead.setSuccessor(finance);

        //责任链处理请求

        manager.handleRequest(request1);

        manager.handleRequest(request2);

        manager.handleRequest(request3);

    }

}

运行代码,结果如下:

5.优缺点

主要优点如下:

(1)责任链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。

(2)请求处理对象仅需维持一个指向其后维者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。

(3)在给对象分派职责时,责任链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。

(4)在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合"开闭原则"的。

主要缺点如下:

(1)由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理。一个请求也可能因责任链没有被正确配置而得不到处理。

(2)对于比较长的责任链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。

(3)如果建链不当,可能会造成循环调用,将导致系统陷入死循环。

6.适用情况

(1)有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。

(2)在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

(3)可动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求,还可以改变链中处理者之间的先后次序。

相关推荐
S-X-S5 分钟前
Java面试题-Redis缓存
java·redis·缓存
带多刺的玫瑰5 分钟前
Leecode刷题C语言之全排列②
java·数据结构·算法
Cherish~~6 分钟前
Mysql8应用架构
java·架构
No8g攻城狮24 分钟前
【异常解决】在idea中提示 hutool 提示 HttpResponse used withoud try-with-resources statement
java·开发语言·ide·intellij-idea
卓怡学长2 小时前
w200基于spring boot的个人博客系统的设计与实现
java·数据库·spring boot·后端·spring·intellij-idea
zhyhgx2 小时前
【Spring】Spring MVC入门(一)
java·spring·mvc
cchjyq2 小时前
opencv:基于暗通道先验(DCP)的内窥镜图像去雾
java·c++·图像处理·人工智能·opencv·计算机视觉
115432031q2 小时前
基于SpringBoot养老院平台系统功能实现十一
java·前端·后端
莫问alicia2 小时前
苍穹外卖 项目记录 day11 Spring Task订单定时处理-来单提醒-客户催单
java·数据库·spring boot·python·spring·mybatis
何中应3 小时前
Spring Boot Actuator使用
java·spring boot·后端