【设计模式】责任链模式教你如何优雅地分发任务

种地  论坛元老 | 2025-3-12 10:59:44 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1041|帖子 1041|积分 3123

概述

在实际生存中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。比方,公司员工告假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要告假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地点等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生存中的“伐鼓传花”游戏等。
定义:
又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起,将全部请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链通报,直到有对象处理它为止。
结构

职责链模式主要包罗以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包罗抽象处理方法和一个后继连接。
  • 详细处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的详细处理者对象提交请求,它不关心处理细节和请求的通报过程。
案例实现

现需要开发一个告假流程控制系统。告假一天以下的假只需要小组长同意即可;告假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行。
类图如下:

代码如下:
  1. //请假条
  2. public class LeaveRequest {
  3.     private String name;//姓名
  4.     private int num;//请假天数
  5.     private String content;//请假内容
  6.     public LeaveRequest(String name, int num, String content) {
  7.         this.name = name;
  8.         this.num = num;
  9.         this.content = content;
  10.     }
  11.     public String getName() {
  12.         return name;
  13.     }
  14.     public int getNum() {
  15.         return num;
  16.     }
  17.     public String getContent() {
  18.         return content;
  19.     }
  20. }
  21. //处理者抽象类
  22. public abstract class Handler {
  23.     protected final static int NUM_ONE = 1;
  24.     protected final static int NUM_THREE = 3;
  25.     protected final static int NUM_SEVEN = 7;
  26.     //该领导处理的请假天数区间
  27.     private int numStart;
  28.     private int numEnd;
  29.     //领导上面还有领导
  30.     private Handler nextHandler;
  31.     //设置请假天数范围 上不封顶
  32.     public Handler(int numStart) {
  33.         this.numStart = numStart;
  34.     }
  35.     //设置请假天数范围
  36.     public Handler(int numStart, int numEnd) {
  37.         this.numStart = numStart;
  38.         this.numEnd = numEnd;
  39.     }
  40.     //设置上级领导
  41.     public void setNextHandler(Handler nextHandler){
  42.         this.nextHandler = nextHandler;
  43.     }
  44.     //提交请假条
  45.     public final void submit(LeaveRequest leave){
  46.         if(0 == this.numStart){
  47.             return;
  48.         }
  49.         //如果请假天数达到该领导者的处理要求
  50.         if(leave.getNum() >= this.numStart){
  51.             this.handleLeave(leave);
  52.             //如果还有上级 并且请假天数超过了当前领导的处理范围
  53.             if(null != this.nextHandler && leave.getNum() > numEnd){
  54.                 this.nextHandler.submit(leave);//继续提交
  55.             } else {
  56.                 System.out.println("流程结束");
  57.             }
  58.         }
  59.     }
  60.     //各级领导处理请假条方法
  61.     protected abstract void handleLeave(LeaveRequest leave);
  62. }
  63. //小组长
  64. public class GroupLeader extends Handler {
  65.     public GroupLeader() {
  66.         //小组长处理1-3天的请假
  67.         super(Handler.NUM_ONE, Handler.NUM_THREE);
  68.     }
  69.     @Override
  70.     protected void handleLeave(LeaveRequest leave) {
  71.         System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
  72.         System.out.println("小组长审批:同意。");
  73.     }
  74. }
  75. //部门经理
  76. public class Manager extends Handler {
  77.     public Manager() {
  78.         //部门经理处理3-7天的请假
  79.         super(Handler.NUM_THREE, Handler.NUM_SEVEN);
  80.     }
  81.     @Override
  82.     protected void handleLeave(LeaveRequest leave) {
  83.         System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
  84.         System.out.println("部门经理审批:同意。");
  85.     }
  86. }
  87. //总经理
  88. public class GeneralManager extends Handler {
  89.     public GeneralManager() {
  90.         //部门经理处理7天以上的请假
  91.         super(Handler.NUM_SEVEN);
  92.     }
  93.     @Override
  94.     protected void handleLeave(LeaveRequest leave) {
  95.         System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
  96.         System.out.println("总经理审批:同意。");
  97.     }
  98. }
  99. //测试类
  100. public class Client {
  101.     public static void main(String[] args) {
  102.         //请假条来一张
  103.         LeaveRequest leave = new LeaveRequest("小花",5,"身体不适");
  104.         //各位领导
  105.         GroupLeader groupLeader = new GroupLeader();
  106.         Manager manager = new Manager();
  107.         GeneralManager generalManager = new GeneralManager();
  108.         groupLeader.setNextHandler(manager);//小组长的领导是部门经理
  109.         manager.setNextHandler(generalManager);//部门经理的领导是总经理
  110.         //之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。
  111.         //提交申请
  112.         groupLeader.submit(leave);
  113.     }
  114. }
复制代码
优缺点

优点:

  • 降低了对象之间的耦合度:该模式降低了请求发送者和接收者的耦合度。
  • 加强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。
  • 加强了给对象指派职责的灵活性:当工作流程发生变革,可以动态地改变链内的成员或者修改它们的序次,也可动态地新增或者删除责任。
  • 责任链简化了对象之间的连接:一个对象只需保持一个指向其后继者的引用,不需保持其他全部处理者的引用,这避免了使用浩繁的 if 或者 if···else 语句。
  • 责任分担:每个类只需要处理自己该处理的工作,不能处理的通报给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
2,缺点:

  • 不能保证每个请求肯定被处理。由于一个请求没有明确的接收者,所以不能保证它肯定会被处理,该请求可能一直传到链的末了都得不到处理。
  • 对比力长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到肯定影响。
  • 职责链创建的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统堕落,如可能会造成循环调用。
源码解析 - FilterChain

在javaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析:

  • 模拟web请求Request以及web响应Response
  1. public interface Request{
  2. }
  3. public interface Response{
  4. }
复制代码

  • 模拟web过滤器Filter
  1. public interface Filter {
  2.      public void doFilter(Request req,Response res,FilterChain c);
  3. }
复制代码

  • 模拟实现详细过滤器
  1. public class FirstFilter implements Filter {
  2.     @Override
  3.     public void doFilter(Request request, Response response, FilterChain chain) {
  4.         System.out.println("过滤器1 前置处理");
  5.         // 先执行所有request再倒序执行所有response
  6.         chain.doFilter(request, response);
  7.         System.out.println("过滤器1 后置处理");
  8.     }
  9. }
  10. public class SecondFilter  implements Filter {
  11.     @Override
  12.     public void doFilter(Request request, Response response, FilterChain chain) {
  13.         System.out.println("过滤器2 前置处理");
  14.         // 先执行所有request再倒序执行所有response
  15.         chain.doFilter(request, response);
  16.         System.out.println("过滤器2 后置处理");
  17.     }
  18. }
复制代码

  • 模拟实现过滤器链FilterChain
  1. public class FilterChain {
  2.     private List<Filter> filters = new ArrayList<Filter>();
  3.     private int index = 0;
  4.     // 链式调用
  5.     public FilterChain addFilter(Filter filter) {
  6.         this.filters.add(filter);
  7.         return this;
  8.     }
  9.     public void doFilter(Request request, Response response) {
  10.         if (index == filters.size()) {
  11.             return;
  12.         }
  13.         Filter filter = filters.get(index);
  14.         index++;
  15.         filter.doFilter(request, response, this);
  16.     }
  17. }
复制代码

  • 测试类
  1. public class Client {
  2.     public static void main(String[] args) {
  3.         Request  req = null;
  4.         Response res = null ;
  5.         FilterChain filterChain = new FilterChain();
  6.         filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
  7.         filterChain.doFilter(req,res);
  8.     }
  9. }
复制代码
往期推荐


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

种地

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表