java设计模式之责任链模式

责任链模式

概念

责任链,顾名思义,就是用来处理相关事务责任的一条执行链,执行链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。

场景一

现实中,请假的OA申请:
请假天数如果是半天到1天,可能直接主管批准即可;
如果是1到3天的假期,需要部门经理批准;
如果是3天到30天,则需要总经理审批;
大于30天,正常不会批准。

类图:

  • 员工提交请求类:LeaveRequest。

  • 抽象的请假责任处理类:AbstractLeaveHandler。

  • 直接主管审批处理类:DirectLeaderLeaveHandler。

  • 部门经理处理类:DeptManagerLeaveHandler。

  • 总经理处理类: GManagerLeaveHandler。

员工请求发起申请到抽象的责任处理类中,根据员工的请假天数,对应的处理类完成处理。 每一个责任处理类设置下面的节点。自身处理不了则传递给下一个节点处理。

代码:

LeaveRequest.java

package com.link.chain.process;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
 * 请假申请
 */
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class LeaveRequest {

 /**天数*/
 private int leaveDays;

 /**姓名*/
 private String name;
}

AbstractLeaveHandler.java

package com.link.chain.process;

/**
 * 请假责任链抽象处理类
 */
public class AbstractLeaveHandler {

 /**
 * 直接主管审批处理的请假天数
 */
 protected int MIN = 1;

 /**
 * 部门经理处理的请假天数
 */
 protected int MIDDLE = 3;

 /**
 * 总经理处理的请假天数
 */
 protected int MAX = 30;

 /**
 * 领导名称
 */
 protected String handlerName;

 /**
 * 下一个处理节点(即更高级别的领导)
 */
 protected AbstractLeaveHandler nextHandler;

 /**
 * 设置下一节点
 */
 protected void setNextHandler(AbstractLeaveHandler handler) {
 this.nextHandler = handler;
 }

 /**
 * 处理请假的请求,子类实现
 */
 protected void handlerRequest(LeaveRequest request) {

 }
}

DirectLeaderLeaveHandler.java

package com.link.chain.process;

/**
 * 主管处理类
 */
public class DirectLeaderLeaveHandler extends AbstractLeaveHandler {

 public DirectLeaderLeaveHandler(String name) {
 this.handlerName = name;
 }

 @Override
 protected void handlerRequest(LeaveRequest request) {
 System.out.println("主管:" + handlerName + ",已经处理;流程结束。");
 if (request.getLeaveDays() <= this.MIN) {
 return;
 }

 if (null != this.nextHandler) {
 this.nextHandler.handlerRequest(request);
 } else {
 System.out.println("审批拒绝!");
 }
 }
}

DeptManagerLeaveHandler.java

package com.link.chain.process;

/**
 * 部门经理处理类
 */
public class DeptManagerLeaveHandler extends AbstractLeaveHandler {

 public DeptManagerLeaveHandler(String name) {
 this.handlerName = name;
 }

 @Override
 protected void handlerRequest(LeaveRequest request) {
 System.out.println("部门经理:" + handlerName + ",已经处理;流程结束。");
 if (request.getLeaveDays() > this.MIN && request.getLeaveDays() <= this.MIDDLE) {
 return;
 }

 if (null != this.nextHandler) {
 this.nextHandler.handlerRequest(request);
 } else {
 System.out.println("审批拒绝!");
 }
 }
}

GManagerLeaveHandler.java

package com.link.chain.process;

/**
 * 总经理处理类
 */
public class GManagerLeaveHandler extends AbstractLeaveHandler {
 public GManagerLeaveHandler(String name) {
 this.handlerName = name;
 }

 @Override
 protected void handlerRequest(LeaveRequest request) {
 System.out.println("总经理:" + handlerName + ",已经处理;流程结束。");
 if (request.getLeaveDays() > this.MIDDLE && request.getLeaveDays() <= this.MAX) {
 return;
 }

 if (null != this.nextHandler) {
 this.nextHandler.handlerRequest(request);
 } else {
 System.out.println("审批拒绝!");
 }
 }
}

Test.java

package com.link.chain.process;

public class Test {
 public static void main(String[] args) {
 LeaveRequest request = LeaveRequest.builder().leaveDays(30).name("小明").build();

 //直接主管
 DirectLeaderLeaveHandler directLeaderLeaveHandler = new DirectLeaderLeaveHandler("陈凡");
 //部门经理
 DeptManagerLeaveHandler deptManagerLeaveHandler = new DeptManagerLeaveHandler("张培进");
 //总经理
 GManagerLeaveHandler gManagerLeaveHandler = new GManagerLeaveHandler("许顺康");

 directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
 deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);
 directLeaderLeaveHandler.handlerRequest(request);
 }
}

场景二

实现下图filter的处理顺序:

request:filter1 >> filter2

response:filter2 >> filter1

执行流程.png

代码:

版本一:

package com.link.chain.filter.v1;

import java.util.ArrayList;
import java.util.List;

/**
 * https://docs.oracle.com/javaee/7/api/
 */
public class Main {
 public static void main(String[] args) {
 Request request = new Request("request");
 Response response = new Response("response");
 FilterChain filterChain = new FilterChain();
 filterChain.add(new HtmlFilter()).add(new SensitiveFilter());
 filterChain.doFilter(request, response);
 System.out.println(request.str);
 }
}

class Request {
 String str;

 Request(String str) {
 this.str = str;
 }
}

class Response {
 String str;

 Response(String str) {
 this.str = str;
 }
}

interface Filter {
 boolean doFilter(Request request, Response response);
}

/**
 * html过滤器
 */
class HtmlFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response) {
 request.str += "-->HtmlFilter";
 return false;
 }
}

/**
 * 敏感词过滤器
 */
class SensitiveFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response) {
 request.str += "-->SensitiveFilter";
 return false;
 }
}

class FilterChain implements Filter {

 private List<Filter> filters = new ArrayList<>();

 public FilterChain add(Filter filter) {
 filters.add(filter);
 return this;
 }

 @Override
 public boolean doFilter(Request request, Response response) {
 for (Filter filter : filters) {
 filter.doFilter(request, response);
 }
 return false;
 }
}

版本二:

package com.link.chain.filter.v2;

import java.util.ArrayList;
import java.util.List;

/**
 * 用最直观的方式处理response
 * 直接将response的处理放在request下面
 */
public class Main {
 public static void main(String[] args) {
 Request request = new Request("request");
 Response response = new Response("response");
 FilterChain filterChain = new FilterChain();
 filterChain.add(new HtmlFilter()).add(new SensitiveFilter());
 filterChain.doFilter(request, response);
 System.out.println(request.str);
 }
}

class Request {
 String str;

 Request(String str) {
 this.str = str;
 }
}

class Response {
 String str;

 Response(String str) {
 this.str = str;
 }
}

interface Filter {
 boolean doFilter(Request request, Response response);
}

/**
 * html过滤器
 */
class HtmlFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response) {
 request.str += "-->HtmlFilter";
 return false;
 }
}

/**
 * 敏感词过滤器
 */
class SensitiveFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response) {
 request.str += "-->SensitiveFilter";
 return false;
 }
}

class FilterChain implements Filter {

 private List<Filter> filters = new ArrayList<>();

 public FilterChain add(Filter filter) {
 filters.add(filter);
 return this;
 }

 @Override
 public boolean doFilter(Request request, Response response) {
 for (Filter filter : filters) {
 filter.doFilter(request, response);
 }
 return false;
 }
}

版本三:

package com.link.chain.filter.v3;

import java.util.ArrayList;
import java.util.List;

/**
 * 在filterChain中加入位置的记录
 * 同时在filter中加入第三个参数
 */
public class Main {
 public static void main(String[] args) {
 Request request = new Request("request");
 Response response = new Response("response");
 FilterChain filterChain = new FilterChain();
 filterChain.add(new HtmlFilter()).add(new SensitiveFilter());
 filterChain.doFilter(request, response, filterChain);
 System.out.println(request.str);
 System.out.println(response.str);
 }
}

class Request {
 String str;

 Request(String str) {
 this.str = str;
 }
}

class Response {
 String str;

 Response(String str) {
 this.str = str;
 }
}

interface Filter {
 boolean doFilter(Request request, Response response, FilterChain filterChain);
}

/**
 * html过滤器
 */
class HtmlFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response, FilterChain filterChain) {
 request.str += "-->HtmlFilter";
 filterChain.doFilter(request, response, filterChain);
 response.str += "-->HtmlFilter";
 return true;
 }
}

/**
 * 敏感词过滤器
 */
class SensitiveFilter implements Filter {

 @Override
 public boolean doFilter(Request request, Response response, FilterChain filterChain) {
 request.str += "-->SensitiveFilter";
 filterChain.doFilter(request, response, filterChain);
 response.str += "-->SensitiveFilter";
 return true;
 }
}

class FilterChain implements Filter {

 private List<Filter> filters = new ArrayList<>();

 private int index = 0;

 FilterChain add(Filter filter) {
 filters.add(filter);
 return this;
 }

 public boolean doFilter(Request request, Response response, FilterChain filterChain) {
 if (index == filters.size()) {
 return false;
 }
 Filter filter = filters.get(index);
 index++;
 return filter.doFilter(request, response, filterChain);
 }
}

版本四:

package com.link.chain.filter.v4;

import java.util.ArrayList;
import java.util.List;

/**
 * 完全模拟Servlet中的FilterChain
 */
public class Main {
 public static void main(String[] args) {
 Request request = new Request("request");
 Response response = new Response("response");
 FilterChain filterChain = new FilterChain();
 filterChain.add(new HtmlFilter()).add(new SensitiveFilter());
 filterChain.doFilter(request, response);
 System.out.println(request.str);
 System.out.println(response.str);
 }
}

class Request {
 String str;

 Request(String str) {
 this.str = str;
 }
}

class Response {
 String str;

 Response(String str) {
 this.str = str;
 }
}

interface Filter {
 void doFilter(Request request, Response response, FilterChain filterChain);
}

/**
 * html过滤器
 */
class HtmlFilter implements Filter {

 @Override
 public void doFilter(Request request, Response response, FilterChain filterChain) {
 request.str += "-->HtmlFilter";
 filterChain.doFilter(request, response);
 response.str += "-->HtmlFilter";
 }
}

/**
 * 敏感词过滤器
 */
class SensitiveFilter implements Filter {

 @Override
 public void doFilter(Request request, Response response, FilterChain filterChain) {
 request.str += "-->SensitiveFilter";
 filterChain.doFilter(request, response);
 response.str += "-->SensitiveFilter";
 }
}

class FilterChain {

 private List<Filter> filters = new ArrayList<>();

 private int index = 0;

 FilterChain add(Filter filter) {
 filters.add(filter);
 return this;
 }

 public void doFilter(Request request, Response response) {
 if (index < filters.size()) {
 }
 Filter filter = filters.get(index);
 index++;
 filter.doFilter(request, response, this);
 }
}

总结

责任链主要重在责任分离处理,让各个节点各司其职。
责任链上的各个节点都有机会处理事务,但是也可能不会受理请求。
责任链比较长,调试时可能会比较麻烦。
责任链一般用于处理流程节点之类的实际业务场景中。
Spring拦截器链、servlet过滤器链等都采用了责任链设计模式。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 责任链模式 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个...
    大萌小路阅读 890评论 0 1
  • 一、责任链模式的定义二、责任链模式的使用场景三、责任链模式UML类图四、责任链模式具体实例五、责任链模式代码实现 ...
    Bfmall阅读 1,164评论 0 1
  • 简述 前面我们了解过动态代理模式以及如何自定义拦截器,但是当拦截器存在多个的时候该如何处理呢? 当你要请假时,请假...
    BestbpF阅读 455评论 0 1
  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设...
    Mr_Rains阅读 2,297评论 0 48
  • 定义 为避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请...
    Cat9527阅读 324评论 0 0