设计模式之责任链模式

831 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

概述

在业务系统中,很多情况下一个请求可以被多个对象处理。例如一个报销单的审批,会经过多个岗位的人处理:

graph LR
员工-- <1W -->项目经理-- <5W -->总经理-- >5W -->董事长;

这个流程就是一个链式结构,称为责任链。链上每一个对象都是请求处理者。员工作为发起人不需要关心具体的处理细节,只需要提交报销单即可。将发送者和请求者的进行解耦。

结构

image.png

Handler抽象处理者

定义了一个处理的接口,一般设计成抽象类。定义一个抽象方法供实现类实现。因为处理者的下个处理还是处理者,因此定义一个抽象处理者类型对象successor。

ConcreteHandler具体处理者

具体处理者实现了抽象处理者中定义的抽象方法,在处理请求之前进行判断,如果可以就处理,否则就将请求转发给后继者,在具体的处理对于访问下一个对象,以便请求的转发。

代码示例

//实体类
@Builder
@Data
public class PurchaseRequest {
    private int number;
}
//抽象处理者
public abstract class Approver {
    protected Approver successer;

    public void setSuccesser(Approver successer) {
        this.successer = successer;
    }

    public abstract void  processRequest(PurchaseRequest purchaseRequest);
}
//具体处理者  项目经理
@Service("Director")
public class Director extends Approver{


    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getNumber()<10000){
            System.out.println("项目经理审批"+purchaseRequest.getNumber());
        }else{
            this.successer.processRequest(purchaseRequest);
        }
    }
}
//具体处理者  总经理
@Service("VicePresident")
public class VicePresident extends Approver {


    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getNumber()<50000){
            System.out.println("总经理审批"+purchaseRequest.getNumber());
        }else{
            this.successer.processRequest(purchaseRequest);
        }
    }
}
//具体处理者  董事长
@Service("President")
public class President extends Approver{


    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getNumber()>50000){
            System.out.println("董事长审批"+purchaseRequest.getNumber());
        }else{
            this.successer.processRequest(purchaseRequest);
        }
    }
}
//客户端
@Resource(name="Director")
private Approver direct;

@Resource(name="President")
private Approver president;

@Resource(name="VicePresident")
private Approver vicePresident;

@Test
public void test(){
    direct.setSuccesser(vicePresident);
    vicePresident.setSuccesser(president);
    PurchaseRequest build = PurchaseRequest.builder().number(20000).build();
    direct.processRequest(build);

}

执行结果

image.png

总结

优点

  1. 职责链使对象无需知道是哪一个对象处理,由客户端负责链的创建,降低系统耦合度
  2. 请求处理者只要维持一个指向后继者的引用,不需要维持它对所有的引用,简化对象的连接
  3. 职责链提供更多的灵活性,可以通过在运行时对链进行动态的增加或修改来增加或改变处理一个请求的职责
  4. 增加一个新的处理者无须修改原有代码,符合开闭原则

缺点

  1. 由于一个请求没有明确的接收者,有可能因未正确配置责任链导致得不到处理
  2. 较长的职责链,系统性能将受到一定影响
  3. 如果建链不当,可能会造成循环调用,导致死循环

适用场景

  1. 有多个对象可以处理同一个请求,具体哪个对象处理请求待运行时再确定
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
  3. 可动态处理一组对象处理的请求,根据不同情况调整不同顺序。