文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

三国演义:责任链模式

2024-12-03 03:57

关注

大家好,我是老田,今天我给大家分享设计模式中的责任链模式。用贴切的生活故事,以及真实项目场景来讲设计模式,最后用一句话来总结这个设计模式。

关于设计模式系列,前面我们已经分享过:

故事

前两天,没事又刷了一遍三国演义,看到关羽身在曹营心在汉,听说刘备在袁绍那里,然后就上演了“过五关,斩六将”。

[[403845]]

关羽过五关斩六将主要内容:

东岭关,守关将名叫孔秀,本是黄巾余党,归降曹操之后,带着五百人奉命防守东岭关。关羽车队从关前通过时,孔秀索要通关文牒,与关羽发生冲突,只一个回合,就被关羽斩杀。

关羽过了东岭关,在要过洛阳时,韩福、孟坦用鹿角拦住道路。先是孟坦挑战,与关羽说翻,交手不敌,孟坦拨马回跑,引关公来追,这样韩福就可以在后面射箭擒拿关公,可谁想到关公赤兔马快,从后面赶上孟坦,一刀就把孟坦给劈了。韩福慌得射了一箭,中关公左臂,关公忍住箭伤,也冲过鹿角,一刀斩杀韩福,于是过洛阳。

在得知关羽过关斩将,东岭关孔秀、洛阳韩福、孟坦都被杀害,卞喜自思难以抵挡关公。于是就假意迎接关公,在镇国寺安排下刀斧手,准备伺机杀死关公。幸亏有镇国寺老方丈普净给警示,关公这才察觉出阴谋,与卞喜闹翻,一刀斩杀卞喜,于是关公过汜水关。

这王植是韩福的亲家,听说韩福被关公杀死,十分愤怒,于是就要为韩福报仇。在关公到达荥阳时,王植在馆驿设宴,宴请关公和二位皇嫂。却是暗中派从事胡班放火,想要烧死关公。但胡班因关公给父亲胡华带信的缘故,向关羽告了密。关羽和二位皇嫂得以提前逃离馆驿,胡班却假意放火,迷惑王植。不过王植后来察觉,杀了胡班,来追关羽时,被关羽斩杀,于是关公过荥阳。

这秦琪不仅是夏侯惇的爱将,更是老将军蔡阳的外甥,奉命守卫黄河渡口,盘查过往船只。关公到黄河渡口时,要找船只渡河,被秦琪拦住,秦琪不仅不放关公等人渡河,反而口出狂言,终于激怒关公,被关公斩杀

这就是关羽过五关斩六将的全部过程。

这个故事情节让我想起了一个设计模式:责任链模式。

其实,我们生活中也有着非常多的责任链模式。比如:基本上每个公司都有自己的OA系统,主要是员工基本信息、请假、调休、报销等功能。如果,我有事需要请假两天,于是登录OA系统,发起请假审批。

由于,对于请假时间的长短公司有如下规定:

小于等于半天,审批环节:项目负责人

大于半天,小于等于1天的,审批环节:项目负责人+技术总监

超过1天,审批环节:项目负责人+技术总监+Boss

可以看得出来,我请假审批流程为项目负责人+技术总监+Boss。

到底什么是责任链设计模式?

什么是责任链模式呢

责任链模式英文解释为:

Avoid coupling the sender of a request to its receiver bygiving more than one object a chance to handle the request.Chainthe receiving objects and pass the request along the chain until anobject handles it.

责任链模式(Chain of Responsibility Pattern)将链中每一个节点都看作一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,会沿着责任链预设的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止,属于行为型设计模式。

责任链模式通用代码

Java实现责任链设计模式如下:

  1. public abstract class Handler { 
  2.         protected Handler nextHandler = null
  3.         public abstract void handle(); 
  4.         public Handler getNextHandler() { 
  5.             return nextHandler; 
  6.         } 
  7.         public void setNextHandler(Handler nextHandler) { 
  8.             this.nextHandler = nextHandler; 
  9.         } 
  10.  
  11. public class HandlerA extends Handler{ 
  12.         @Override 
  13.         public void handle() { 
  14.             if(nextHandler == null){ 
  15.                 System.out.println("HandlerA handle ..."); 
  16.             }else
  17.                 nextHandler.handle(); 
  18.             } 
  19.         } 
  20.  
  21. public class HandlerB extends Handler{ 
  22.         @Override 
  23.         public void handle() { 
  24.             if(nextHandler == null){ 
  25.                 System.out.println("HandlerB handle ..."); 
  26.             }else
  27.                 nextHandler.handle(); 
  28.             } 
  29.         } 
  30.  
  31. public class HandlerC extends Handler{ 
  32.     @Override 
  33.     public void handle() { 
  34.         if(getNextHandler() == null){ 
  35.             System.out.println("HandlerC handle ..."); 
  36.         }else
  37.             getNextHandler().handle(); 
  38.         } 
  39.     } 
  40. //测试 
  41. public class  Client{ 
  42.     public static void main(String[] args) { 
  43.         Handler handlerA = new HandlerA(); 
  44.         Handler handlerB = new HandlerB(); 
  45.         handlerA.setNextHandler(handlerB); 
  46.         handlerA.handle(); 
  47.     } 

运行结果:

  1. HandlerC handle ... 

从上面代码,我们可以画出UML图:

从UML图中,我们又可以看出,责任链模式中有两个非常重要的角色:

(1)、抽象处理者角色(Handler)

定义处理请求的接口。接口可以也可以给出一个方法以设定和返回对下个对象引用。这个角色通常由一个Java抽象类或者Java接口实现。

(2)、具体处理者角色(HandlerA、HandlerB、HandlerC)

具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下个对象。由于具体处理者持有对下家的引用。

责任链模式的优缺点

生活中的案例

在日常生活中,责任链模式是比较常见的。我们平时处理工作中的一些事务,往往是各部门协同合作来完成某一个任务的。而每个部门都有各自的职责,因此,很多时候事情完成一半,便会转交到下一个部门,直到所有部门都审批通过,事情才能完成。

责任链模式主要解耦了请求与处理,客户只需将请求发送到链上即可,不需要关心请求的具体内容和处理细节,请求会自动进行传递,直至有节点对象进行处理。

责任链模式主要适用于以下应用场景:

请假流程的代码实现

下面我们来对,前面的案例:OA上请假流程做一个Java代码的实现。

抽象处理者:领导类

  1. public abstract class Leader { 
  2.     private Leader next
  3.     public void setNext(Leader next) { 
  4.         this.next = next
  5.     } 
  6.     public Leader getNext() { 
  7.         return next
  8.     } 
  9.     //处理请求的方法 
  10.     public abstract void handleRequest(double LeaveDays); 

项目负责人

  1. public class ProjectLeader extends Leader { 
  2.     @Override 
  3.     public void handleRequest(double LeaveDays) { 
  4.         if (LeaveDays <= 0.5) { 
  5.             System.out.println("项目负责人批准您请假" + LeaveDays + "天。"); 
  6.         } else { 
  7.             if (getNext() != null) { 
  8.                 getNext().handleRequest(LeaveDays); 
  9.             } else { 
  10.                 System.out.println("请假天数太多,没有人批准该假条!"); 
  11.             } 
  12.         } 
  13.     } 

技术总监

  1. public class TechnicalDirectorLeader extends Leader { 
  2.  
  3.     @Override 
  4.     public void handleRequest(double LeaveDays) { 
  5.         if (LeaveDays <= 1) { 
  6.             System.out.println("技术总监批准您请假" + LeaveDays + "天。"); 
  7.         } else { 
  8.             if (getNext() != null) { 
  9.                 getNext().handleRequest(LeaveDays); 
  10.             } else { 
  11.                 System.out.println("请假天数太多,没有人批准该假条!"); 
  12.             } 
  13.         } 
  14.     } 

Boss

  1. public class BossLeader extends Leader { 
  2.     @Override 
  3.     public void handleRequest(double LeaveDays) { 
  4.         if (LeaveDays >= 2 && LeaveDays <= 30) { 
  5.             System.out.println("Boss批准您请假" + LeaveDays + "天。"); 
  6.         } else { 
  7.             if (getNext() != null) { 
  8.                 getNext().handleRequest(LeaveDays); 
  9.             } else { 
  10.                 System.out.println("请假天数太多,没有人批准该假条!"); 
  11.             } 
  12.         } 
  13.     } 

发起审批

  1. public class LeaveApproval { 
  2.     public static void main(String[] args) { 
  3.         //组装责任链 
  4.         Leader projectLeader = new ProjectLeader(); 
  5.         Leader technicalDirectorLeader = new TechnicalDirectorLeader(); 
  6.         Leader bossLeader = new BossLeader(); 
  7.  
  8.         projectLeader.setNext(technicalDirectorLeader); 
  9.         technicalDirectorLeader.setNext(bossLeader); 
  10.  
  11.         //请假两天,提交请假流程,开启审批环节, 
  12.         projectLeader.handleRequest(2); 
  13.     } 

审批结果

  1. Boss批准您请假2.0天。 

如果请假天数是31天,审批结果

  1. 请假天数太多,没有人批准该假条! 

整个请假流程为:

把这张流程图改成纵向:

就这么一环套一环的,使用上面两个例子和两张图来理解责任链模式是不是就更轻松了?

自己吹牛逼,没什么用,下面来看看大神们是怎么使用责任链模式的。

大佬们是如何使用的

在Spring、Mybatis等框架中,都用使用到责任链模式,下面先来看在Spring中是如何使用的。

在Spring MVC中的org.springframework.web.servlet.DispatcherServlet类中:

getHandler 方法的处理使用到了责任链模式,handlerMappings是之前 Spring 容器初始化好的,通过遍历 handlerMappings查找与request匹配的 Handler, 这里返回 HandlerExecutionChain 对象。这个 HandlerExecutionChain对象到后面执行的时候再分析为什么返回的是这样一个对象。

  1. @Nullable 
  2. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 
  3.  if (this.handlerMappings != null) { 
  4.   for (HandlerMapping mapping : this.handlerMappings) { 
  5.    HandlerExecutionChain handler = mapping.getHandler(request); 
  6.    if (handler != null) { 
  7.     return handler; 
  8.    } 
  9.   } 
  10.  } 
  11.  return null

以上便是责任链模式在Spring的具体使用,关于Mybatis中责任链模式的使用,请看这篇文章:

总结

本文通过关二爷的过五关斩六将和OA系统中的请假审批流程,完美的解释了责任链设计模式。

最后用一句话来总结责任链模式:

各人自扫门前雪,莫管他人瓦上霜。

本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。

 

来源:Java后端技术全栈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯