当前位置:   article > 正文

设计模式——职责链模式(附代码示例)

职责链

一. 传统方式

        以学校采购审批为例,不同金额的采购需要不同人员的审批

1. 传统方式解决

        收到请求后,通过不同的金额调用对应的审批方法

2. 传统方式存在问题

        Client会使用到分支判断(比如switch)来对不同的采购请求处理, 这样就存在如下问题:

                (1)如果各个级别的人员审批金额发生变化,客户端的也需要变化

                (2)客户端必须明确知道有多少个审批级别和访问

        这样对一个采购请求进行处理和Approver(审批人)就存在强耦合关系,不利于代码的扩展和维护。故引出职责链模式。

二. 职责链模式

1. 概念

        职责链模式(Chain of Responsibility Pattern),又叫责任链模式,为请求创建了一个接收者对象的链,属于行为型模式。这种模式对请求的发送者和接收者进行解耦。

        职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

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

2. 职责链模式原理类图

        Handler:抽象的处理者,定义了一个处理请求的接口,同时含有另外Handler

        ConcreteHandlerA, B:具体的处理者,处理它自己负责的请求,可以访问它的后继者 (即下一个处理者),如果可以处理当前请求则处理,否则就将该请求交个后继者去处理,从而形成一个职责链

        Request:含有很多属性,表示一个请求

3. 代码示例

类图

         PurchaseRequest类,表示一个请求

  1. public class PurchaseRequest {
  2. private int type;//请求类型
  3. private float price = 0.0f;
  4. private int id = 0;
  5. public PurchaseRequest(int type, float price, int id) {
  6. this.type = type;
  7. this.price = price;
  8. this.id = id;
  9. }
  10. public int getType() {
  11. return type;
  12. }
  13. public float getPrice() {
  14. return price;
  15. }
  16. public int getId() {
  17. return id;
  18. }
  19. }

         Approver抽象类,抽象的处理者,定义了一个处理请求的接口,同时含有另外Approver

  1. public abstract class Approver {
  2. Approver approver;
  3. String name;
  4. public Approver(String name) {
  5. this.name = name;
  6. }
  7. //下一个处理者
  8. public void setApprover(Approver approver) {
  9. this.approver = approver;
  10. }
  11. //处理审批请求的方法,得到一个请求,处理是子类实现
  12. public abstract void processRequest(PurchaseRequest purchaseRequest);
  13. }

        DepartmentApprove类,继承Approver抽象类,表示系领导处理

  1. public class DepartmentApprove extends Approver{
  2. public DepartmentApprove(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void processRequest(PurchaseRequest purchaseRequest) {
  7. if(purchaseRequest.getPrice()<=5000){
  8. System.out.println("请求编号:"+purchaseRequest.getId()+"被"+this.name+"处理");
  9. }else {
  10. approver.processRequest(purchaseRequest);
  11. }
  12. }
  13. }

        CollegeApprove类,继承Approver抽象类,表示院领导处理

  1. public class CollegeApprove extends Approver{
  2. public CollegeApprove(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void processRequest(PurchaseRequest purchaseRequest) {
  7. if(purchaseRequest.getPrice()>=5000&&purchaseRequest.getPrice()<=50000){
  8. System.out.println("请求编号:"+purchaseRequest.getId()+"被"+this.name+"处理");
  9. }else {
  10. approver.processRequest(purchaseRequest);
  11. }
  12. }
  13. }

        SchoolApprove类,继承Approver抽象类,表示校领导处理

  1. public class SchoolApprove extends Approver{
  2. public SchoolApprove(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void processRequest(PurchaseRequest purchaseRequest) {
  7. if(purchaseRequest.getPrice()>=500000){
  8. System.out.println("请求编号:"+purchaseRequest.getId()+"被"+this.name+"处理");
  9. }
  10. }
  11. }

         Client类,模拟学校处理审批过程

  1. public class Client {
  2. public static void main(String[] args) {
  3. PurchaseRequest purchaseRequest1 = new PurchaseRequest(1, 1000, 1);
  4. PurchaseRequest purchaseRequest2 = new PurchaseRequest(2, 50000, 2);
  5. PurchaseRequest purchaseRequest3 = new PurchaseRequest(2, 500001, 3);
  6. DepartmentApprove departmentApprove = new DepartmentApprove("系领导");
  7. CollegeApprove collegeApprove = new CollegeApprove("院领导");
  8. SchoolApprove schoolApprove = new SchoolApprove("校领导");
  9. //设置下一级处理人
  10. departmentApprove.setApprover(collegeApprove);
  11. collegeApprove.setApprover(schoolApprove);
  12. //都从系领导开始处理
  13. departmentApprove.processRequest(purchaseRequest1);
  14. departmentApprove.processRequest(purchaseRequest2);
  15. departmentApprove.processRequest(purchaseRequest3);
  16. }
  17. }

 输出结果

三. 总结

1. 优点

        将请求和处理分开,实现解耦,提高系统的灵活性

        简化了对象,使对象不需要知道链的结构

2. 不足

        性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能

        调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂

3. 适用场景

        多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器等

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/385604
推荐阅读
相关标签
  

闽ICP备14008679号