当前位置:首页>编程知识库>后端开发知识>设计模式是什么鬼(责任链)
设计模式是什么鬼(责任链)
阅读 1
2018-11-12

//本文作者:凸凹里歐

//本文收录菜单栏:《设计模式是什么鬼》专栏中

曾经有这么一些零散的功能节点,他们各自承担各自的义务,分工明确,各司其职。为了更高效,更完整地解决客户的问题,他们发扬团队精神,互相串联起来形成一个有序的责任传递链表,于是责任链模式诞生了。当然,它的结构也不一定非得是链表,甚至可以是树型分叉结构,这要根据业务场景看怎样去灵活运用,但其核心意义是为了处理某种连续的流程,并确保业务一定能走到相应的责任节点上并得到相应的处理。
说到这里想必大家已经想到了工作流吧?对,企事业单位中通常为了完成某项日常任务,通常要制定一些工作流程,按步骤拆分,并组织好各个环节中的逻辑关系及走向,这样才能更高效、更规范地完成任务。
根据以上流程图,我们来做一个最简单的例子。假设某公司针对出差报销业务制定审批流程,有三个审批角色分别是员工(1000元权限)、经理(5000元权限)、以及CEO10000元权限),各审批人代码如下。
%201public%20class%20Staff%20%7B%0A%202%0A%203%20%20%20%20private%20String%20name;%0A%204%0A%205%20%20%20%20public%20Staff(String%20name)%20%7B%0A%206%20%20%20%20%20%20%20%20this.name%20=%20name;%0A%207%20%20%20%20%7D%0A%208%0A%209%20%20%20%20public%20boolean%20approve(int%20amount)%20%7B%0A10%20%20%20%20%20%20%20%20if%20(amount%20<=%201000)%20%7B%0A11%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A12%20%20%20%20%20%20%20%20%20%20%20%20return%20true;%0A13%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A14%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E8%AF%B7%E6%89%BE%E4%B8%8A%E7%BA%A7%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A15%20%20%20%20%20%20%20%20%20%20%20%20return%20false;%0A16%20%20%20%20%20%20%20%20%7D%0A17%20%20%20%20%7D%0A18%0A19%7D%0A
%201public%20class%20Manager%20%7B%0A%202%0A%203%20%20%20%20private%20String%20name;%0A%204%0A%205%20%20%20%20public%20Manager(String%20name)%20%7B%0A%206%20%20%20%20%20%20%20%20this.name%20=%20name;%0A%207%20%20%20%20%7D%0A%208%0A%209%20%20%20%20public%20boolean%20approve(int%20amount)%20%7B%0A10%20%20%20%20%20%20%20%20if%20(amount%20<=%205000)%20%7B%0A11%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A12%20%20%20%20%20%20%20%20%20%20%20%20return%20true;%0A13%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A14%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E8%AF%B7%E6%89%BE%E4%B8%8A%E7%BA%A7%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A15%20%20%20%20%20%20%20%20%20%20%20%20return%20false;%0A16%20%20%20%20%20%20%20%20%7D%0A17%20%20%20%20%7D%0A18%0A19%7D%0A
%201public%20class%20CEO%20%7B%0A%202%0A%203%20%20%20%20private%20String%20name;%0A%204%0A%205%20%20%20%20public%20CEO(String%20name)%20%7B%0A%206%20%20%20%20%20%20%20%20this.name%20=%20name;%0A%207%20%20%20%20%7D%0A%208%0A%209%20%20%20%20public%20boolean%20approve(int%20amount)%20%7B%0A10%20%20%20%20%20%20%20%20if%20(amount%20<=%2010000)%20%7B%0A11%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90CEO%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A12%20%20%20%20%20%20%20%20%20%20%20%20return%20true;%0A13%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A14%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E9%A9%B3%E5%9B%9E%E7%94%B3%E8%AF%B7%E3%80%82%E3%80%90CEO%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A15%20%20%20%20%20%20%20%20%20%20%20%20return%20false;%0A16%20%20%20%20%20%20%20%20%7D%0A17%20%20%20%20%7D%0A18%0A19%7D%0A
好了,审批人们定义完毕,逻辑非常简单缜密,如果超过审批金额最大权限则打回去,开始写申请人客户端类。
%201public%20class%20Client%20%7B%0A%202%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%203%20%20%20%20%20%20%20%20int%20amount%20=%2010000;//%E5%87%BA%E5%B7%AE%E8%8A%B1%E8%B4%B910000%E5%85%83%0A%204%20%20%20%20%20%20%20%20//%20%E5%85%88%E6%89%BE%E5%91%98%E5%B7%A5%E5%BC%A0%E9%A3%9E%E5%AE%A1%E6%89%B9%0A%205%20%20%20%20%20%20%20%20Staff%20staff%20=%20new%20Staff(%22%E5%BC%A0%E9%A3%9E%22);%0A%206%20%20%20%20%20%20%20%20if%20(!staff.approve(amount))%20%7B%0A%207%20%20%20%20%20%20%20%20%20%20%20%20//%E8%A2%AB%E6%8B%92%EF%BC%8C%E6%89%BE%E5%85%B3%E4%BA%8C%E7%88%B7%E9%97%AE%E9%97%AE%E3%80%82%0A%208%20%20%20%20%20%20%20%20%20%20%20%20Manager%20manager%20=%20new%20Manager(%22%E5%85%B3%E7%BE%BD%22);%0A%209%20%20%20%20%20%20%20%20%20%20%20%20if%20(!manager.approve(amount))%20%7B%0A10%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%E8%BF%98%E6%98%AF%E8%A2%AB%E6%8B%92%EF%BC%8C%E5%8F%AA%E8%83%BD%E6%89%BE%E8%80%81%E5%A4%A7%E4%BA%86%E3%80%82%0A11%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CEO%20ceo%20=%20new%20CEO(%22%E5%88%98%E5%A4%87%22);%0A12%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ceo.approve(amount);%0A13%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A14%20%20%20%20%20%20%20%20%7D%0A15%20%20%20%20%20%20%20%20/***********************%0A16%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E8%AF%B7%E6%89%BE%E4%B8%8A%E7%BA%A7%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%E5%BC%A0%E9%A3%9E%E3%80%91%0A17%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E8%AF%B7%E6%89%BE%E4%B8%8A%E7%BA%A7%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%E5%85%B3%E7%BE%BD%E3%80%91%0A18%20%20%20%20%20%20%20%20%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90CEO%EF%BC%9A%E5%88%98%E5%A4%87%E3%80%91%0A19%20%20%20%20%20%20%20%20***********************/%0A20%20%20%20%20%7D%0A21%7D%0A
功夫不负有心人,跑了三个地方找了三个人,一万元的大额报销单终于被大老板审批了。然而,大家有没有发现问题?我们走的审批流程好像有点过于复杂了,找这个不行那个不同意,跑来跑去的好像自己有点像是被踢皮球的感觉。此外,如果我们后期要优化完善此工作流程,或是添加新的审批角色进来,那就得不停地修改此处的逻辑,最终的修改结果会是?
乱了,全乱套了,我们终将被淹没在一堆复杂的审批流程中,跑断腿也找不到门路。这显然是违反设计模式原则的,我们必须进行重构。我们观察此类中的审批逻辑,这显然就是一个链式结构,审批人之间环环相扣,对于自己无法处理的申请,会像被踢皮球似的传给上级,直到某人解决此申请,对员工张飞来说,他只知道自己传球给关羽了,仅此而已。
进一步分析,审批人肯定是不同的角色,并且每个角色的审批逻辑会有区别,所以我们得把这些角色的审批逻辑分开来写,对每个角色的责任范围我们进行定义,我只懂自己怎么审批(责任),我处理不了的我递交给上层(链条),开始重构,先抽象出一个审批人类。
%201public%20abstract%20class%20Approver%20%7B//%20%E5%AE%A1%E6%89%B9%E4%BA%BA%E6%8A%BD%E8%B1%A1%E7%B1%BB%0A%202%0A%203%20%20%20%20protected%20String%20name;//%20%E6%8A%BD%E8%B1%A1%E5%87%BA%E5%AE%A1%E6%89%B9%E4%BA%BA%E7%9A%84%E5%A7%93%E5%90%8D%E3%80%82%0A%204%20%20%20%20protected%20Approver%20nextApprover;//%20%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%AE%A1%E6%89%B9%E4%BA%BA%EF%BC%8C%E6%9B%B4%E9%AB%98%E7%BA%A7%E5%88%AB%E9%A2%86%E5%AF%BC%E3%80%82%0A%205%0A%206%20%20%20%20public%20Approver(String%20name)%20%7B%0A%207%20%20%20%20%20%20%20%20this.name%20=%20name;%0A%208%20%20%20%20%7D%0A%209%0A10%20%20%20%20protected%20Approver%20setNextApprover(Approver%20nextApprover)%20%7B%0A11%20%20%20%20%20%20%20%20this.nextApprover%20=%20nextApprover;%0A12%20%20%20%20%20%20%20%20return%20this.nextApprover;//%20%E8%BF%94%E5%9B%9E%E4%B8%8B%E4%B8%AA%E5%AE%A1%E6%89%B9%E4%BA%BA%EF%BC%8C%E9%93%BE%E5%BC%8F%E7%BC%96%E7%A8%8B%E3%80%82%0A13%20%20%20%20%7D%0A14%0A15%20%20%20%20public%20abstract%20void%20approve(int%20amount);//%20%E6%8A%BD%E8%B1%A1%E5%AE%A1%E6%89%B9%E6%96%B9%E6%B3%95%E7%94%B1%E5%85%B7%E4%BD%93%E5%AE%A1%E6%89%B9%E4%BA%BA%E5%AD%90%E7%B1%BB%E5%AE%9E%E7%8E%B0%0A16%7D
注意第4行,审批人只认识自己的领导,所以会持有下一级领导的引用,同时第10行的代码用于把领导注入进来。第15行是我们的审批方法了,但每个角色审批逻辑会有区别,所以这里进行抽象,并由具体的审批角色子类去实现,先从员工看起。
%201public%20class%20Staff%20extends%20Approver%20%7B%0A%202%0A%203%20%20%20%20public%20Staff(String%20name)%20%7B%0A%204%20%20%20%20%20%20%20%20super(name);%0A%205%20%20%20%20%7D%0A%206%0A%207%20%20%20%20@Override%0A%208%20%20%20%20public%20void%20approve(int%20amount)%20%7B%0A%209%20%20%20%20%20%20%20%20if%20(amount%20<=%201000)%20%7B%0A10%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A11%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A12%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A13%20%20%20%20%20%20%20%20%20%20%20%20this.nextApprover.approve(amount);%0A14%20%20%20%20%20%20%20%20%7D%0A15%20%20%20%20%7D%0A16%0A17%7D
很简单,员工类继承了审批角色类,第9行申明审批权限为1000元,重点在于第13行这里调用了自己上级领导的审批方法,显然这里是自己处理不了的申请单了。大同小异,再重构经理及CEO审批角色类。
%201public%20class%20Manager%20extends%20Approver%20%7B%0A%202%0A%203%20%20%20%20public%20Manager(String%20name)%20%7B%0A%204%20%20%20%20%20%20%20%20super(name);%0A%205%20%20%20%20%7D%0A%206%0A%207%20%20%20%20@Override%0A%208%20%20%20%20public%20void%20approve(int%20amount)%20%7B%0A%209%20%20%20%20%20%20%20%20if%20(amount%20<=%205000)%20%7B%0A10%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A11%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A12%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A13%20%20%20%20%20%20%20%20%20%20%20%20this.nextApprover.approve(amount);%0A14%20%20%20%20%20%20%20%20%7D%0A15%20%20%20%20%7D%0A16%0A17%7D%0A
%201public%20class%20CEO%20extends%20Approver%20%7B%0A%202%0A%203%20%20%20%20public%20CEO(String%20name)%20%7B%0A%204%20%20%20%20%20%20%20%20super(name);%0A%205%20%20%20%20%7D%0A%206%0A%207%20%20%20%20@Override%0A%208%20%20%20%20public%20void%20approve(int%20amount)%20%7B%0A%209%20%20%20%20%20%20%20%20if%20(amount%20<=%2010000)%20%7B%0A10%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90CEO%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A11%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A12%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E9%A9%B3%E5%9B%9E%E7%94%B3%E8%AF%B7%E3%80%82%E3%80%90CEO%EF%BC%9A%22%20 %20name%20 %20%22%E3%80%91%22);%0A13%20%20%20%20%20%20%20%20%7D%0A14%20%20%20%20%7D%0A15%0A16%7D%0A
CEO类作为链条的尾巴,也就是最高级别,第12行的越权逻辑会最终拒绝申请单。很简单吧?我们生成一下这个链条,并从员工开始传递申请单。
%201public%20class%20Client%20%7B%0A%202%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%203%20%20%20%20%20%20%20%20Approver%20flightJohn%20=%20new%20Staff(%22%E5%BC%A0%E9%A3%9E%22);%0A%204%20%20%20%20%20%20%20%20flightJohn.setNextApprover(new%20Manager(%22%E5%85%B3%E7%BE%BD%22)).setNextApprover(new%20CEO(%22%E5%88%98%E5%A4%87%22));%0A%205%0A%206%20%20%20%20%20%20%20%20//%E9%AB%98%E5%B1%82%E6%8E%A5%E8%A7%A6%E4%B8%8D%E5%88%B0%E4%B9%9F%E6%B2%A1%E5%BF%85%E8%A6%81%E6%8E%A5%E8%A7%A6%EF%BC%8C%E7%9B%B4%E6%8E%A5%E6%89%BE%E5%91%98%E5%B7%A5%E5%BC%A0%E9%A3%9E%E5%AE%A1%E6%89%B9%E3%80%82%0A%207%20%20%20%20%20%20%20%20flightJohn.approve(1000);%0A%208%20%20%20%20%20%20%20%20/***********************%0A%209%20%20%20%20%20%20%20%20%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%E5%BC%A0%E9%A3%9E%E3%80%91%0A10%20%20%20%20%20%20%20%20***********************/%0A11%0A12%20%20%20%20%20%20%20%20flightJohn.approve(4000);%0A13%20%20%20%20%20%20%20%20/***********************%0A14%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%E5%BC%A0%E9%A3%9E%E3%80%91%0A15%20%20%20%20%20%20%20%20%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%E5%85%B3%E7%BE%BD%E3%80%91%0A16%20%20%20%20%20%20%20%20***********************/%0A17%0A18%20%20%20%20%20%20%20%20flightJohn.approve(9000);%0A19%20%20%20%20%20%20%20%20/***********************%0A20%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%E5%BC%A0%E9%A3%9E%E3%80%91%0A21%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%E5%85%B3%E7%BE%BD%E3%80%91%0A22%20%20%20%20%20%20%20%20%E5%AE%A1%E6%89%B9%E9%80%9A%E8%BF%87%E3%80%82%E3%80%90CEO%EF%BC%9A%E5%88%98%E5%A4%87%E3%80%91%0A23%20%20%20%20%20%20%20%20***********************/%0A24%0A25%20%20%20%20%20%20%20%20flightJohn.approve(88000);%0A26%20%20%20%20%20%20%20%20/***********************%0A27%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E5%91%98%E5%B7%A5%EF%BC%9A%E5%BC%A0%E9%A3%9E%E3%80%91%0A28%20%20%20%20%20%20%20%20%E6%97%A0%E6%9D%83%E5%AE%A1%E6%89%B9%EF%BC%8C%E5%8D%87%E7%BA%A7%E5%A4%84%E7%90%86%E3%80%82%E3%80%90%E7%BB%8F%E7%90%86%EF%BC%9A%E5%85%B3%E7%BE%BD%E3%80%91%0A29%20%20%20%20%20%20%20%20%E9%A9%B3%E5%9B%9E%E7%94%B3%E8%AF%B7%E3%80%82%E3%80%90CEO%EF%BC%9A%E5%88%98%E5%A4%87%E3%80%91%0A30%20%20%20%20%20%20%20%20***********************/%0A31%20%20%20%20%7D%0A32%7D%0A
这里注意第4行的代码对责任链进行构造(其实这里我们还可以交由工作流工厂去构造完成,读者可以自己实践练习),从员工开始一直到CEO结束。之后的业务就非常简单了,直接递单给员工张飞,审批流程便魔法般地启动了,审批单在这个责任链条上层层递交,最终给出结果。
至此,申请人与审批人实现了解耦,我们只需递单送给责任链即可,申请人不必再关心每个处理细节,只需交给接口人张飞处理就妥了。使用了责任链模式后的代码看起来非常简洁,各个角色的责任划分非常明确并且被分开定义到了每个角色类中,再把他们串起来去调用,一气呵成。后期如果再继续添加新的角色只需要添加新角色类并加入链条即可,链条的随意伸缩,灵活的可伸缩性,完美的可扩展性。挂上这条钛合金项链,维护世界和平的责任就交给你了!
在实际应用中,我们切勿生搬硬套,还需根据实际需求场景进行灵活运用,就拿工业现代化生产线举例,这个其实也类似责任链模式,但不同之处在于其组装工作是必须经过每个组装节点处理的,从头到尾的全链处理而不能中途退出,读者朋友可以自己写代码练习,实践与思考要相结合并循环往复,二者都非常重要。
点击图片加入Spring交流群
↓↓↓
看完本文有收获?请转发分享给更多人
以上数据来源于网络,如有侵权,请联系删除。
评论 (0)