应用场景

http web请求处理,请求过来后将经过转码、解析、参数封装、鉴权等一系列的处理(责任),而且要经过多少处理是可以灵活调整的

那么该怎么做呢?

将所有的处理都写在一个类中行不行呢?

分成多个类又该如何灵活的组合在一起呢?

简单示例

Request类:

public interface Request {
//do something...
}

ResponsibilityChain类:

public class ResponsibilityChain {

    private List<Responsibility> responsibilityList = new ArrayList<>();

    private Integer index = 0;

    public void process(Request request) {
if (this.index < responsibilityList.size()) {
this.responsibilityList.get(index++).process(request, this);
}
} /** 加入链中 */
public void register(Responsibility responsibility) {
this.responsibilityList.add(responsibility);
}
}

Responsibility接口:

public interface Responsibility {
void process(Request request, ResponsibilityChain chain);
}

Responsibility实现类:

public class ResponsibilityA implements Responsibility {
@Override
public void process(Request request, ResponsibilityChain chain) {
System.out.println("转码");
chain.process(request);
}
}
public class ResponsibilityB implements Responsibility {
@Override
public void process(Request request, ResponsibilityChain chain) {
System.out.println("解析");
chain.process(request);
}
}
public class ResponsibilityC implements Responsibility {
@Override
public void process(Request request, ResponsibilityChain chain) {
System.out.println("参数封装");
chain.process(request);
}
}
public class ResponsibilityD implements Responsibility {
@Override
public void process(Request request, ResponsibilityChain chain) {
System.out.println("鉴权");
chain.process(request);
}
}

测试类:

public class Test {
public static void main(String[] args) {
ResponsibilityChain chain = new ResponsibilityChain();
chain.register(new ResponsibilityA());
chain.register(new ResponsibilityB());
chain.register(new ResponsibilityC());
chain.register(new ResponsibilityD());
chain.process(new Request() {
});
}
}



类图:

责任链模式

定义

所有的处理者,都加入到这个链式,一个处理完后,转给下一个

或者说每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者

  1. 抽象出责任接口,具体责任逻辑实现接口
  2. 根据处理过程需要,将具体实现组合成链
  3. 使用者使用链

典型的代表:Filter、Interceptor

意图

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止

主要解决问题

职责链上的处理者负责处理请求,客户端只需要将请求发送到职责链上就行了,不需要关系处理的细节和请求的传递,请求的发送者和处理者解耦了

何时使用

  1. 系统已经有一个由处理者对象组成的链,这个链可能有合成模式给出
  2. 有多于一个的处理者对象会处理一个请求,而且事先并不清楚到底由哪一个处理者对象处理一个请求,处理者对象是动态确定的
  3. 系统想发出一个请求给多个处理者对象中的某一个,但是不明显指定哪一个处理者对象会处理该请求
  4. 处理一个请求的处理者对象集合需要动态的指定时

优缺点

优点:

  1. 发送者和接收者解耦,低耦合
  2. 简化了对象。使得对象不需要知道链的结构
  3. 通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
  4. 增加新的请求处理类很方便

缺点:

  1. 不能保证请求一定被接收
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
  3. 可能不容易观察运行时的特征,有碍于除错

类图如下:



涉及到的角色:

  1. 抽象处理者(Handler)角色:定义一个处理请求的接口,如果需要,接口可以定义出一个方法,以设定和返回对下家的引用,这个角色通常由一个抽象类或者接口实现
  2. 具体处理者(ConcreteHandler)角色:具体处理者接收到请求后,可以选择将请求处理掉,或者传给下一个;具体处理者持有对下一个的引用,因此如果需要,具体处理者可以访问下一个

代码示例:

Handler类:

public abstract class Handler {

    protected Handler successor;

    /** 调用此方法处理请求 */
public abstract void handlerRequest(); /** 取值方法 */
public Handler getSuccessor() {
return successor;
} /** 调用此方法设置下一个 */
public void setSuccessor(Handler successor) {
this.successor = successor;
}
}

ConcreteHandler类:

public class ConcreteHandler1 extends Handler {
@Override
public void handlerRequest() {
if (getSuccessor() != null) {
System.out.println("请求传递到下一个:" + getSuccessor().getClass().getName());
getSuccessor().handlerRequest();
} else {
System.out.println("请求在ConcreteHandler1被处理了");
}
}
}
public class ConcreteHandler2 extends Handler {
@Override
public void handlerRequest() {
if (getSuccessor() != null) {
System.out.println("请求传递到下一个:" + getSuccessor());
getSuccessor().handlerRequest();
} else {
System.out.println("请求在ConcreteHandler2被处理了");
}
}
}

客户端:

public class Client {

    static private Handler handler1;

    static private Handler handler2;

    public static void main(String[] args) {
handler1 = new ConcreteHandler1();
handler2 = new ConcreteHandler2();
handler1.setSuccessor(handler2);
handler1.handlerRequest();
}
}

类图:

击鼓传花的故事

击鼓传花是一种热闹而又紧张的饮酒游戏,在酒宴上宾客依次坐定,由一人击鼓,开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在谁手里,谁就开始饮酒了;下面以《红楼梦》中击鼓传花的故事,写一个小例子:



抽象接口Player类:

public abstract class Player {

    private Player player;

    /** 需要执行酒令的请求 */
abstract public void handlerRequest(int index); /** 设置下一个传花人 */
public void setPlayer(Player player) {
this.player = player;
} /** 将花传给下一家,如果没有就结束 */
public void next(int index) {
if (player != null) {
player.handlerRequest(index);
} else {
System.out.println("传花结束");
}
}
}

参与击鼓传花的人:

public class JiaMu extends Player {

    public JiaMu(Player player) {
this.setPlayer(player);
} @Override
public void handlerRequest(int index) {
if (index == 1) {
System.out.println("贾母执行酒令");
} else {
System.out.println("贾母将花传给下一个");
next(index);
}
}
}
public class JiaShe extends Player {

    public JiaShe(Player player) {
this.setPlayer(player);
} @Override
public void handlerRequest(int index) {
if (index == 2) {
System.out.println("贾赦执行酒令");
} else {
System.out.println("贾赦将花传给下一个");
next(index);
}
}
}
public class JiaZheng extends Player {

    public JiaZheng(Player player) {
this.setPlayer(player);
} @Override
public void handlerRequest(int index) {
if (index == 3) {
System.out.println("贾政执行酒令");
} else {
System.out.println("贾政将花传给下一个");
next(index);
}
}
}
public class JiaBaoYu extends Player {

    public JiaBaoYu(Player player) {
this.setPlayer(player);
} @Override
public void handlerRequest(int index) {
if (index == 4) {
System.out.println("贾宝玉执行酒令");
} else {
System.out.println("贾宝玉将花传给下一个");
next(index);
}
}
}
public class JiaHuan extends Player {

    public JiaHuan(Player player) {
this.setPlayer(player);
} @Override
public void handlerRequest(int index) {
if (index == 5) {
System.out.println("贾环执行酒令");
} else {
System.out.println("贾环将花传给下一个");
next(index);
}
}
}

击鼓者:

public class DrinkingGame {

    static private Player player;

    public static void main(String[] args) {
player = new JiaMu(
new JiaShe(
new JiaZheng(
new JiaBaoYu(
new JiaHuan(null)))));
//设置第四个执行酒令
player.handlerRequest(4);
}
}



类图:

击鼓传花联想到了Java设计模式:责任链模式的更多相关文章

  1. 【设计模式】Java设计模式 - 责任链模式

    [设计模式]Java设计模式 - 责任链模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 目录 [设计模式]Java设计模式 - 责 ...

  2. java 设计模式 -- 责任链模式

    设计模式 – 责任链模式 介绍: 责任链模式是一种动态行为模式,有多个对象,每一个对象分别拥有其下家的引用.连起来形成一条链.待处理对象则传到此链上,在此链进行传递,且待处理对象并不知道此会被链上的哪 ...

  3. Java设计模式の责任链模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其 ...

  4. 我的Java设计模式-责任链模式

    今天来说说程序员小猿和产品就关于需求发生的故事.前不久,小猿收到了产品的需求. 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的. 小猿:......露点?你大爷的,让身为正义与纯 ...

  5. Java设计模式-责任链模式

    提出问题: 最初接触责任链模式就是在struts2中,在当时学的时候看了一眼,大概知道了原理,最近在复习,模拟struts2,说是模拟只是大体模拟了struts2的工作流程,很多东西都是写死的,只是为 ...

  6. Java设计模式-责任链模式(Chain of Responsibility)

    接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求.但是发出者并不清楚到底最终那个对象会处理该请求,所以,责任 ...

  7. Java设计模式—责任链模式

    责任链模式的定义: 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止. 责任链模式的重点是在"链& ...

  8. 浅谈Python设计模式 -- 责任链模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...

  9. Java与设计模式-责任链模式

    责任链模式属于行为型设计模式之中的一个,怎么理解责任链?责任链是能够理解成数个对象首尾连接而成,每个节点就是一个对象.每个对象相应不同的处理逻辑,直至有一个对象响应处理请求结束.这一种模式成为责任链模 ...

随机推荐

  1. 如何把数据放到C#的心里之 DB2实例

    平时偶尔因为工作需要得自己写一些小工具去操作数据库,因为只是需要实现一些小的功能,也不涉及多类型的数据库,也许就是一次性的使用.所以此时那些大而全的数据库操作框架,也就不再那么适合我了.而本篇博文主要 ...

  2. 3分钟学会如何上手supervisor看门狗

    软硬件环境 centos7.6.1810 64bit cat /etc/redhat-release #查看系统版本 supervisor 3.4.0 python 2.7.5 supervisor简 ...

  3. WPF -- 一种实现本地化的方法

    本文介绍一种WPF程序实现本地化的方法. 步骤 首先,假设xaml文件中存在一个Button按钮,内容为"按钮",实现本地化的步骤如下: 展开程序的Properties,双击Res ...

  4. apiAutoTest:支持自定义函数,用例中可调用

    0. 前言 apiAutoTest从去年8月以来开源至今,也更新了不少内容,一起来看看吧 第一个版本 - 2020/08/08 增加实际响应存储数据的方法,并在字典可以处理依赖见tools/svae_ ...

  5. 如何系统的了解Kafka

    1.概述 在大数据的浪潮下,时时刻刻都会产生大量的数据.比如社交媒体.博客.电子商务等等,这些数据会以不同的类型存储在不同的平台里面.为了执行ETL(提取.转换.加载)操作,需要一个消息中间件系统,该 ...

  6. 用量子计算模拟器ProjectQ生成随机数,并用pytest进行单元测试与覆盖率测试

    技术背景 本文中主要包含有三个领域的知识点:随机数的应用.量子计算模拟产生随机数与基于pytest框架的单元测试与覆盖率测试,这里先简单分别介绍一下背景知识. 随机数的应用 在上一篇介绍量子态模拟采样 ...

  7. ISC BIND9 - 最详细、最认真的从零开始的BIND 9 服务讲解

    DNS and BIND 服务的搭建说明 目录 目录 DNS and BIND 服务的搭建说明 1. 背景 1.1 DNS 1.2 FQDN 1.3 BIND 1.4 本文中搭建模拟DNS服务网络虚拟 ...

  8. E: Some index files failed to download. They have been**

    转: E: Some index files failed to download. They have been** 问题描述: 当使用Dockerfile从包含cuda的镜像建立新的image的时 ...

  9. const成员函数可以将非const指针作为返回值吗?

    先给出一段代码 class A { int *x; public: int *f() const { return x; } }; 成员函数f返回指向私有成员 x 的非常量指针,我认为这会修改成员x ...

  10. 为 APK 文件增加右键菜单组实现快捷安装

    0.结果 1.需求 迫于每次都要打开 Powershell 手动敲 adb install xxx.apk 太麻烦,就想通过注册表搞一个右键菜单,实现快捷安装 apk 的功能. 最后决定先实现三个功能 ...