1 学校 OA 系统的采购审批项目:需求是

采购员采购教学器材

1) 如果金额 小于等于 5000,  由教学主任审批 (0<=x<=5000)

2) 如果金额 小于等于 10000,  由院长审批 (5000<x<=10000)

3) 如果金额 小于等于 30000,  由副校长审批 (10000<x<=30000)

4) 如果金额 超过 30000 以上,有校长审批 ( 30000<x)

请设计程序完成采购审批项目

2 传统方案解决 OA 系统审批,传统的设计方案(类图)

3 传统方案解决 OA 系统审批问题分析

1) 传统方式是:接收到一个采购请求后,根据采购金额来调用对应的 Approver (审批人)完成审批。

2) 传统方式的问题分析 :  客户端这里会使用到 分支判断(比如  switch)  来对不同的采购请求处理, 这样就存在如下问题 (1) 如果各个级别的人员审批金额发生变化,在客户端的也需要变化 (2) 客户端必须明确的知道  有多少个审批级别和访问

3) 这样 对一个采购请求进行处理 和 Approver (审批人) 就存在强耦合关系,不利于代码的扩展和维护

4) 解决方案 =》 职责链模式

4 职责链模式基本介绍

基本介绍

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

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

3) 这种类型的设计模式属于行为型模式

5 职责链模式的原理类图

  • 对原理类图的说明-即(职责链模式的角色及职责)

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

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

3) Request , 含义很多属性,表示一个请求

6 职责链模式解决 OA 系统采购审批

1) 应用实例要求

编写程序完成学校 OA 系统的采购审批项目:需求采购员采购教学器材

如果金额 小于等于 5000, 由教学主任审批

如果金额 小于等于 10000, 由院长审批

如果金额 小于等于 30000, 由副校长审批

如果金额 超过 30000 以上,有校长审批

2)思路分析和图解(类图)

3)代码实现

package com.lin.responsibilitychain;

public class PurchaseRequest {

    private int type;
private float price = 0.0f;
private int id = 0; public PurchaseRequest(int type, float price, int id) {
super();
this.type = type;
this.price = price;
this.id = id;
} public int getType() {
return type;
} public float getPrice() {
return price;
} public int getId() {
return id;
} }
package com.lin.responsibilitychain;

public abstract class Approver {

    Approver approver;

    String name;

    public Approver(String name) {
super();
this.name = name;
} // 下一个处理者
public void setApprover(Approver approver) {
this.approver = approver;
} // 处理审判请求的方法,得到一个请求,处理是子类完成的,因此该方法是抽象的
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
package com.lin.responsibilitychain;

public class DepartmentApprover extends Approver{

    public DepartmentApprover(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void processRequest(PurchaseRequest purchaseRequest) {
// TODO Auto-generated method stub
if(purchaseRequest.getPrice() <= 5000) {
System.out.println("请求编号 id = " + purchaseRequest.getId() + "被" + this.name + "处理");
} else {
approver.processRequest(purchaseRequest);
}
} }
package com.lin.responsibilitychain;

public class CollegeApprover extends Approver {

    public CollegeApprover(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
System.out.println("请求编号 id = " + purchaseRequest.getId() + "被" + this.name + "处理");
} else {
approver.processRequest(purchaseRequest);
}
} }
package com.lin.responsibilitychain;

public class ViceSchoolMasterApprove extends Approver {
public ViceSchoolMasterApprove(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <= 30000) {
System.out.println("请求编号 id = " + purchaseRequest.getId() + "被" + this.name + "处理");
} else {
approver.processRequest(purchaseRequest);
}
} }
package com.lin.responsibilitychain;

public class SchoolMasterApprover extends Approver {
public SchoolMasterApprover(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 30000) {
System.out.println("请求编号 id = " + purchaseRequest.getId() + "被" + this.name + "处理");
} else {
approver.processRequest(purchaseRequest);
}
} }
package com.lin.responsibilitychain;

public class Client {

    public static void main(String[] args) {
PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000, 1); DepartmentApprover departmentApprover = new DepartmentApprover("张主任");
CollegeApprover collegeApprover = new CollegeApprover("林院长");
ViceSchoolMasterApprove viceSchoolMasterApprove = new ViceSchoolMasterApprove("李副校长");
SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("王校长"); // 需要将各个审批级别的下一个设置好(环状)
departmentApprover.setApprover(collegeApprover);
collegeApprover.setApprover(viceSchoolMasterApprove);
viceSchoolMasterApprove.setApprover(schoolMasterApprover);
schoolMasterApprover.setApprover(departmentApprover); departmentApprover.processRequest(purchaseRequest);
}
}

7 职责链模式在 SpringMVC 框架应用的源码分析

1) SpringMVC-HandlerExecutionChain 类就使用到职责链模式

2) SpringMVC 请求流程简图

3) 代码分析

4) 对源码总结

  • springmvc 请求的流程图中,执行了 拦截器相关方法 interceptor.preHandler 等等
  • 在处理 SpringMvc 请求时,使用到职责链模式还使用到适配器模式
    • HandlerExecutionChain 主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只是将请求分配给链上注册处理器执行,这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程
  • HandlerExecutionChain 维护了 HandlerInterceptor 的集合, 可以向其中注册相应的拦截器.

8 职责链模式的注意事项和细节

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

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

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

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

5) 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web 中 Tomcat

对 Encoding 的处理、拦截器

仅供参考,有错误还请指出!

有什么想法,评论区留言,互相指教指教。

觉得不错的可以点一下右边的推荐哟

设计模式(二十四)——职责链模式(SpringMVC源码分析)的更多相关文章

  1. 二十:职责链模式详解(类似于spring的hangler处理请求)

    定义:为了避免请求的发送者和接收者之间的耦合关系,使多个接受对象都有机会处理请求.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. “看这个定义,就是将一堆可以处理请求的对象连 ...

  2. 设计模式(九)——装饰者模式(io源码分析)

    1 星巴克咖啡订单项目(咖啡馆): 1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡).ShortBlack.LongBlack(美式咖啡).Decaf(无因咖啡) 2) 调料:Milk.So ...

  3. 重温设计模式(三)——职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

  4. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  5. springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)

    在之前的博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMethodMapping的父类AbstractHandlerMa ...

  6. springMVC源码分析--国际化实现Session和Cookie(二)

    上一篇博客springMVC源码分析--国际化LocaleResolver(一)中我们介绍了springMVC提供的国际化的解决方案,接下来我们根据springMVC提供的解决方案来简单的实现一个多语 ...

  7. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  8. springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)

    在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...

  9. springMVC源码分析--HttpRequestHandlerAdapter(四)

    上一篇博客springMVC源码分析--HandlerAdapter(一)中我们主要介绍了一下HandlerAdapter接口相关的内容,实现类及其在DispatcherServlet中执行的顺序,接 ...

  10. springMVC源码分析--SimpleServletHandlerAdapter(二)

    上一篇博客springMVC源码分析--HandlerAdapter(一)中我们主要介绍了一下HandlerAdapter接口相关的内容,实现类及其在DispatcherServlet中执行的顺序,接 ...

随机推荐

  1. C# 静态类 单例模式 对比

    公司的类都需要使用单例模式实现,这个可以节省资源,避免重复对象的生成.但是静态类也可以做到这一点,而且写起来更简洁,于是查阅相关资料,希望弄明白两者的差别. 1.单例模式可以在用到的时候初始化,而静态 ...

  2. spring-cloud-netflix-eureka-server

    一.构建springcloud父pom工程,管理版本 pom.xml <?xml version="1.0" encoding="UTF-8"?> ...

  3. 域渗透——获得域控服务器的NTDS.dit文件

    0x00 前言 在之前的文章<导出当前域内所有用户hash的技术整理>曾介绍过通过Volume Shadow Copy实现对ntds.dit文件的复制, 可用来导出域内所有用户hash.本 ...

  4. Windows 10 & git & bash

    Windows 10 & git & bash If you are on Windows, we recommend downloading Git for Windows and ...

  5. Vue & Sentry sourcemaps All In One

    Vue & Sentry sourcemaps All In One vue & sentry & sourcemaps https://docs.sentry.io/plat ...

  6. cheerio & jQuery for server

    cheerio & jQuery for server Fast, flexible & lean implementation of core jQuery designed spe ...

  7. 开放式 Web 应用程序安全性项目 OWASP

    开放式 Web 应用程序安全性项目 OWASP Open Web Application Security Project (OWASP) OWASP 基金会是谁? Open Web Applicat ...

  8. JWT & JSON Web Tokens

    JSON Web Tokens https://jwt.io json web token example https://jwt.io/introduction/ https://medium.co ...

  9. chrome device remote debug

    chrome device remote debug chrome://inspect/#devices chrome inspect devices Android chrome MIDI / MT ...

  10. NGK是如何运用IPFS分布式存储的?

    整个夏季,除了天气的火热,还有的火热莫过于IPFS挖矿这个领域了.IPFS的概念火热到,你可以看到到处都在卖IPFS矿机.那么,是什么原因导致IPFS这么火呢?在这之前,我们先了解一下什么是IPFS技 ...