设计模式之责任链模式

一、什么是责任链模式

责任链模式,为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一个对象记住下一个对象的引用,而成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

责任链模式,也叫职责链模式,属于行为型设计模式。

二、责任链模式类图

设计模式之责任链模式插图

三、责任链模式角色

  • 抽象处理者角色(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后续连接。
  • 具体处理者角色(ConcreteHandler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理则处理,否则该请求转给它的后继者。

四、责任链模式优缺点

1、优点

  1. 降低了请求者和接受者对象之间的耦合度。
  2. 增强了系统的可扩展性,新增处理类时,满足开闭原则。
  3. 增强了给对象指派职责的灵活性:当流程工作发生变化时,可以根据需要动态调整责任链的顺序,也可新增或删除责任链。
  4. 责任链简化了对象之间的连接:一个责任链只需保持一个其后继者的引用,无需保持其它处理者的引用。
  5. 责任链分工明确:每个责任链只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,满足单一职责原则

2、缺点

  1. 不能保证每个请求都能被处理。
  2. 对比较长的责任链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  3. 责任链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能由于责任链的错误设置而导致系统出错。

五、责任链模式demo示例

1、Demo需求

以请假审批流程为例,公司员工请假审批流程是:员工请假天数小于3天,小组长审批;请假天数小于10天,部门经理审批;请假天数小于20天,副总经理审批;请假天数小于30天,总经理审批;请假天数超过30天,不予审批。

2、数据类定义

/**
  * 请假类
  */ public class LeaveRequest {
     //请假人
     private String name;
     //请假理由
     private String reason;
     //请假天数
     private int day;
 
     public LeaveRequest(String name, String reason, int day) {
         this.name = name;
         this.reason = reason;
         this.day = day;
     }
 
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this.name = name;
     }
 
     public String getReason() {
         return reason;
     }
 
     public void setReason(String reason) {
         this.reason = reason;
     }
 
     public int getDay() {
         return day;
     }
 
     public void setDay(int day) {
         this.day = day;
     }
 }

3、抽象类定义

/**
  * 抽象处理者角色:请假流程抽象类
  */ public  abstract class Leader {
     //审批人
     protected String name;
     //下一个审批者
     protected Leader nextLeader;
 
     public Leader(String name) {
         this.name = name;
     }
 
     public void setNextLeader(Leader nextLeader) {
         this.nextLeader = nextLeader;
     }
 
     /**
      * 请假审批
      * @param request
      */     public abstract void approve(LeaveRequest request);
 }

4、具体化对象类

/**
  * 具体处理者角色:小组长审批
  */ public class Headman extends Leader {
 
     public Headman(String name) {
         super(name);
     }
 
     public void approve(LeaveRequest request) {
         //审批请假天数小于3天
         if(request.getDay()<=3){
             System.out.println("请假人:"+request.getName()+", 请假天数:"+request.getDay()+", 请假理由:"+request.getReason());
             System.out.println("小组长:"+name+"审批通过");
         }else {
             if(nextLeader != null){
                 nextLeader.approve(request);
             }
         }
     }
 }
/**
  * 具体处理者角色:部门经理审批
  */ public class DepartmentManager extends Leader {
 
     public DepartmentManager(String name) {
         super(name);
     }
 
     public void approve(LeaveRequest request) {
         //审批请假天数大于3天小于10天
         if(request.getDay()<=10){
             System.out.println("请假人:"+request.getName()+", 请假天数:"+request.getDay()+", 请假理由:"+request.getReason());
             System.out.println("部门经理:"+name+"审批通过");
         }else {
             if(nextLeader != null){
                 nextLeader.approve(request);
             }
         }
     }
 }
/**
  * 具体处理者角色:副总经理审批
  */ public class ViceGeneralManager extends Leader {
 
     public ViceGeneralManager(String name) {
         super(name);
     }
 
     public void approve(LeaveRequest request) {
         /**
          * 审批天数大于10小于20天
          */         if(request.getDay()<=20){
             System.out.println("请假人:"+request.getName()+", 请假天数:"+request.getDay()+", 请假理由:"+request.getReason());
             System.out.println("副总经理:"+name+"审批通过");
         }else {
             if(nextLeader != null){
                 nextLeader.approve(request);
             }
         }
     }
 }
/**
  * 具体处理者角色:总经理审批
  */ public class GeneralManager extends Leader {
 
     public GeneralManager(String name) {
         super(name);
     }
 
     public void approve(LeaveRequest request) {
         //审批请假天数大于20天小于30天
         if (request.getDay() <= 30) {
             System.out.println("请假人:" + request.getName() + ", 请假天数:" + request.getDay() + ", 请假理由:" + request.getReason());
             System.out.println("总经理:" + name + "审批通过");
         } else {
             if (nextLeader != null) {
                 nextLeader.approve(request);
             } else {
                 System.out.println("请假人:" + request.getName() + ", 请假天数:" + request.getDay() + ", 请假理由:" + request.getReason());
                 System.out.println("请假天数太长无法审批,请提交请假天数小于30天。");
             }
         }
     }
 }

5、测试

/**
  * 责任链模式客户端测试类
  */ public class Client {
     public static void main(String[] args) {
         Headman director = new Headman("李大帅");
         DepartmentManager manager = new DepartmentManager("老王");
         ViceGeneralManager viceGeneralManager = new ViceGeneralManager("赵副");
         GeneralManager generalManager = new GeneralManager("胡总");
         director.setNextLeader(manager);
         manager.setNextLeader(viceGeneralManager);
         viceGeneralManager.setNextLeader(generalManager);
 
         LeaveRequest leaveRequest = new LeaveRequest("小王", "感冒了!", 1);
         director.approve(leaveRequest);
         System.out.println("============================================");
         leaveRequest = new LeaveRequest("小李", "加班调休!", 6);
         director.approve(leaveRequest);
         System.out.println("============================================");
         leaveRequest = new LeaveRequest("小胡", "回家探亲!", 12);
         director.approve(leaveRequest);
         System.out.println("============================================");
         leaveRequest = new LeaveRequest("小吴", "回家探亲!", 30);
         director.approve(leaveRequest);
         System.out.println("============================================");
         leaveRequest = new LeaveRequest("小张", "生病休养!", 36);
         director.approve(leaveRequest);
     }
 }
请假人:小王, 请假天数:1, 请假理由:感冒了!
小组长:李大帅审批通过
============================================
请假人:小李, 请假天数:6, 请假理由:加班调休!
部门经理:老王审批通过
============================================
请假人:小胡, 请假天数:12, 请假理由:回家探亲!
副总经理:赵副审批通过
============================================
请假人:小吴, 请假天数:30, 请假理由:回家探亲!
总经理:胡总审批通过
============================================
请假人:小张, 请假天数:36, 请假理由:生病休养!
请假天数太长无法审批,请提交请假天数小于30天。

发表评论