设计模式-责任链模式

原理和实现

将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收 对象能够处理它为止,实时上,在常见的使用场景中,我们的责任链并不是和概念中的完全一样
● 原始概念中,是直到链上的某个接收对象能够处理它为止
● 实际使用中,链上的所有对象都可以对请求进行特殊处理

实现方式

使用链表实现

  1. 定义虚拟类Handler
package com.hillky.desgin_learn.chainResponsibility;public abstract class Handler {protected Handler successor = null;public void setSuccessor(Handler successor) {this.successor = successor;}public abstract void handle();
}
  1. 定义具体处理器
package com.hillky.desgin_learn.chainResponsibility;public class HandlerA extends Handler{@Overridepublic void handle() {boolean handled = false;
//...if (!handled && successor != null) {successor.handle();}}
}package com.hillky.desgin_learn.chainResponsibility;public class HandlerB extends Handler{@Overridepublic void handle() {boolean handled = false;
//...if (!handled && successor != null) {successor.handle();}}
}
  1. 创建HandlerChain
package com.hillky.desgin_learn.chainResponsibility;public class HandlerChain {private Handler head = null;private Handler tail = null;public void addHandler(Handler handler) {handler.setSuccessor(null);if (head == null) {head = handler;tail = handler;return;}tail.setSuccessor(handler);tail = handler;}public void handle() {if (head != null) {head.handle();}}
}
  1. 使用测试
package com.hillky.desgin_learn.chainResponsibility;public class Client {public static void main(String[] args) {HandlerChain chain = new HandlerChain();chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}

处理器类的 handle() 函数,不仅包含自己的业 务逻辑,还包含对下一个处理器的调用,也就是代码中的 successor.handle()。一个不熟悉这种代码结构的程序员,在添加新的处理器类的时候,很有可能忘记在handle() 函数中调用 successor.handle(),这就会导致代码出现 bug。

针对这个问题,我们对代码进行重构,利用模板模式,将调用 successor.handle() 的逻辑从具体的处理器类中剥离出来,放到抽象父类中。

package com.hillky.desgin_learn.chainResponsibility;public abstract class Handler {protected Handler successor = null;public void setSuccessor(Handler successor) {this.successor = successor;}public abstract boolean doHandle();public final void handle() {boolean handled = doHandle();if (successor != null && !handled) {successor.handle();}}
}package com.hillky.desgin_learn.chainResponsibility;public class HandlerA extends Handler{@Overridepublic boolean doHandle() {boolean handled = false;System.out.println("Handler A在处理");
//...return handled;}
}

使用数组实现

这种实现方式更加简单。 HandlerChain 类用数组而非链表来保存所有的处理器,并且需要在 HandlerChain 的 handle() 函数中,依次调用每个处理器的 handle() 函数。

  1. Handler接口
package com.hillky.desgin_learn.chainResponsibility.array;public interface IHandler {boolean handle();
}
  1. Handler具体实现
package com.hillky.desgin_learn.chainResponsibility.array;import javax.xml.ws.handler.Handler;public class HandlerA implements IHandler {@Overridepublic boolean handle() {boolean handled = false;System.out.println("HandlerA 处理");return handled;}
}package com.hillky.desgin_learn.chainResponsibility.array;public class HandlerB implements IHandler {@Overridepublic boolean handle() {boolean handled = false;System.out.println("HandlerB 处理");return handled;}
}
  1. HandlerChain
package com.hillky.desgin_learn.chainResponsibility.array;import java.util.ArrayList;
import java.util.List;public class HandlerChain {private List<IHandler> handlers = new ArrayList<>();public void addHandler(IHandler handler){handlers.add(handler);}public void handle() {for (IHandler handler : handlers) {boolean handled = handler.handle();if (handled) {break;}}}
}
  1. 测试
package com.hillky.desgin_learn.chainResponsibility.array;
public class Client {public static void main(String[] args) {HandlerChain chain = new HandlerChain();chain.addHandler(new HandlerA());chain.addHandler(new HandlerB());chain.handle();}
}

源码实现

Servlet Filter

Servlet Filter 是 Java Servlet 规范中定义的组件,翻译成中文就是过滤器,它可以实 现对 HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等等。因为它是 Servlet 规范的一部分,所以,只要是支持 Servlet 的 Web 容器(比如,Tomcat、 Jetty 等),都支持过滤器功能。

可以自定义实现过滤器配置到web中(chatgpt搜索实现)

简单的示例

  1. 创建一个名为 RequestTimingFilter 的 Java 类,实现 javax.servlet.Filter 接口
package com.hillky.desgin_learn.chainResponsibility.filter;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class RequestTimingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 在请求到达时记录开始时间long startTime = System.currentTimeMillis();// 将请求传递给责任链上的下一个 Filter 或目标 Servletchain.doFilter(request, response);// 在请求处理完成后记录结束时间,并计算耗时long endTime = System.currentTimeMillis();long timeElapsed = endTime - startTime;HttpServletRequest httpServletRequest = (HttpServletRequest) request;String requestURI = httpServletRequest.getRequestURI();System.out.println("请求 " + requestURI + " 的访问耗时:" + timeElapsed + " 毫秒");}
}
  1. 注册到我们的web工程中(添加注解)
package com.hillky.desgin_learn;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication
@EnableAspectJAutoProxy
@ServletComponentScan // 扫描Servlet组件
public class DesginLearnApplication {public static void main(String[] args) {SpringApplication.run(DesginLearnApplication.class, args);}}
package com.hillky.desgin_learn.chainResponsibility.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@WebFilter(urlPatterns = "/*")
public class RequestTimingFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 在请求到达时记录开始时间long startTime = System.currentTimeMillis();// 将请求传递给责任链上的下一个 Filter 或目标 Servletchain.doFilter(request, response);// 在请求处理完成后记录结束时间,并计算耗时long endTime = System.currentTimeMillis();long timeElapsed = endTime - startTime;HttpServletRequest httpServletRequest = (HttpServletRequest) request;String requestURI = httpServletRequest.getRequestURI();System.out.println("请求 " + requestURI + " 的访问耗时:" + timeElapsed + " 毫秒");}
}

Spring Interceptor

刚刚讲了 Servlet Filter,现在我们来讲一个功能上跟它非常类似的东西,Spring Interceptor,翻译成中文就是拦截器。尽管英文单词和中文翻译都不同,但这两者 基本上可以看作一个概念,都用来实现对 HTTP 请求进行拦截处理。

它们不同之处在于,Servlet Filter 是 Servlet 规范的一部分,实现依赖于 Web 容 器。Spring Interceptor 是 Spring MVC 框架的一部分,由 Spring MVC 框架来提 供实现。客户端发送的请求,会先经过 Servlet Filter,然后再经过 Spring Interceptor,最后到达具体的业务代码中。

简单的示例

  1. 定义Interceptor
public class RequestTimingInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在请求到达时记录开始时间long startTime = System.currentTimeMillis();request.setAttribute("startTime", startTime);// 返回 true 以将请求传递给责任链上的下一个 Interceptor 或目标 Controllerreturn true;
//        return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在请求处理完成后记录结束时间,并计算耗时long endTime = System.currentTimeMillis();long startTime = (Long) request.getAttribute("startTime");long timeElapsed = endTime - startTime;String requestURI = request.getRequestURI();System.out.println("请求 " + requestURI + " 的访问耗时:" + timeElapsed + "毫秒");}
}
  1. 在你的 Spring 配置类中,注册并配置这个 Interceptor

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new RequestTimingInterceptor());}
}
  1. 当你的 Spring 应用收到 HTTP 请求时, RequestTimingInterceptor 将会拦截这个请求,并在请求处理前后记录时间。

应用场景

  1. 日志记录器:在应用程序中,我们可能需要将日志记录到不同的位置,如控制 台、文件、数据库等。我们可以创建一个日志记录器链,每个记录器处理特定级别的日志,然后将请求传递给下一个记录器。这样,可以根据日志级别灵活地记录日志信息。
  2. Web 应用中的过滤器和拦截器:在 Web 应用程序中,我们经常需要对请求进行 预处理和后处理,如身份验证、授权、编码转换、请求日志记录等。过滤器和拦截器就是典型的使用责任链模式的场景,请求和响应在过滤器或拦截器链中依次传递,每个过滤器或拦截器执行特定的任务。
  3. 工作流引擎:在一个工作流引擎中,一个请求可能需要经过多个处理步骤,这些步骤可以看作是一个责任链。每个处理器处理请求的一个部分,然后将请求传递给下一个处理器,直到请求被完全处理。

实践

对于支持 UGC(User Generated Content,用户生成内容)的应用(比如论坛)来 说,用户生成的内容(比如,在论坛中发表的帖子)可能会包含一些敏感词(比如涉 黄、广告、反动等词汇)。针对这个应用场景,我们就可以利用职责链模式来过滤这 些敏感词。 过滤敏感词
在这个应用场景中,我们可以创建一个过滤器链来过滤用户生成的内容。每个过滤器 负责处理一种类型的敏感词,然后将内容传递给下一个过滤器。以下是一个简单的实现示例:

  1. 定义一个过滤器接口
public interface ContentFilter {String filter(String content);
}
  1. 实现不同类型的过滤器,例如涉黄过滤器、广告过滤器和反动过滤器
package com.hillky.desgin_learn.chainResponsibility.ugc;public class PornographyFilter implements ContentFilter{@Overridepublic String filter(String content) {// 这里用简单的字符串替换来表示过滤操作,实际应用中需要更复杂的过滤逻辑return content.replaceAll("涉黄词汇", "***");}}package com.hillky.desgin_learn.chainResponsibility.ugc;// 广告过滤器
public class AdvertisementFilter implements ContentFilter {@Overridepublic String filter(String content) {return content.replaceAll("广告词汇", "***");}
}package com.hillky.desgin_learn.chainResponsibility.ugc;// 反动过滤器
public class ReactionaryFilter implements ContentFilter {@Overridepublic String filter(String content) {return content.replaceAll("反动词汇", "***");}
}
  1. 创建一个过滤器链
package com.hillky.desgin_learn.chainResponsibility.ugc;import java.util.ArrayList;
import java.util.List;public class FilterChain {private List<ContentFilter> filters=new ArrayList<>();public FilterChain addFilter(ContentFilter filter) {filters.add(filter);return this;}public String doFilter(String content) {for (ContentFilter filter : filters) {content = filter.filter(content);}return content;}
}
  1. 测试
package com.hillky.desgin_learn.chainResponsibility.ugc;public class Client {public static void main(String[] args) {// 创建一个过滤器链FilterChain filterChain = new FilterChain();filterChain.addFilter(new PornographyFilter()).addFilter(new AdvertisementFilter()).addFilter(new ReactionaryFilter());// 用户生成的内容String userContent = "这里有一些涉黄词汇,这里有一些广告词汇,这里有一些反动词汇。";// 使用过滤器链处理内容String filteredContent = filterChain.doFilter(userContent);System.out.println(filteredContent);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/54691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python|OpenCV-读取视频,显示视频并保存视频(3)

前言 本文是该专栏的第3篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 在使用OpenCV处理视频的时候,不论是摄像头画面还是视频文件,通常情况下都要使用VideoCapture类来进行每一帧图像的处理。对于OpenCV而言,只要使用视频文件作为参数,它就可以打开视频文件…

在前端开发中,什么叫移动设备上的视口?如何通过header标签中的meta属性设置页面的视口。

移动设备上的视口&#xff08;Viewport&#xff09;是指在移动设备上可见的网页区域。由于移动设备的屏幕尺寸和分辨率各不相同&#xff0c;为了确保网页在各种设备上都能正确显示和交互&#xff0c;需要通过视口设置来适配不同的屏幕尺寸。 在移动设备上&#xff0c;网页通常…

Qt XML文件解析 QDomDocument

QtXml模块提供了一个读写XML文件的流&#xff0c;解析方法包含DOM和SAX,两者的区别是什么呢&#xff1f; DOM&#xff08;Document Object Model&#xff09;&#xff1a;将XML文件保存为树的形式&#xff0c;操作简单&#xff0c;便于访问。 SAX&#xff08;Simple API for …

SpringBoot2.0集成WebSocket

<!-- websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency> 新建配置类 import org.springframework.boot.autoconfigure.condition.Cond…

视频监控/视频集中存储/云存储平台AI智能分析网关V3——功能简介

安防监控/视频集中存储/云存储平台AI智能分析网关V3内置了20多种AI算法&#xff0c;可针对安全生产、通用园区、智慧食安、石油化工等场景&#xff0c;提供基于视频智能检测技术的个性化行业解决方案。今天来具体介绍下v3版本的智能分析网关有哪些算法功能配置。 一、硬件 安防…

DDR与PCIe:高性能SoC的双引擎

SoC芯片无处不在&#xff0c;小到家电控制的MCU&#xff0c;大到手机芯片&#xff0c;我们都会接触到。如今大部分芯片设计公司都在开发SoC芯片&#xff0c;一颗SoC芯片可以集成越来越多的功能&#xff0c;俨然它已成为IC设计业界的焦点。 高性能、高速、高带宽的互联和存储的…

深入分析负载均衡情景

本文出现的内核代码来自Linux5.4.28&#xff0c;为了减少篇幅&#xff0c;我们尽量不引用代码&#xff0c;如果有兴趣&#xff0c;读者可以配合代码阅读本文。 一、有几种负载均衡的方式&#xff1f; 整个Linux的负载均衡器有下面的几个类型&#xff1a; 实际上内核的负载均衡…

Git push拦截

遇到的问题 今天想提交代码到gitee&#xff0c;结果发现被拦截了&#xff0c;有段提示“forbidden by xxxx”… 我记得xxxx好像是公司的一个防泄密的东西… 这个东西是怎么实现的呢&#xff1f; 解决 原来git提供很多hook&#xff0c;push命令就有一个pre-push的hook&#x…

如何保障Facebook账号登录稳定

当谈到保障Facebook账号的稳定性时&#xff0c;我们不得不提到那些令人头疼的情况——Facebook账号被封。尽管我们已经踏入数字化的未来&#xff0c;但是被封号似乎是一个时常困扰着社交媒体用户的问题。那么&#xff0c;让我们来看看一些常见的Facebook账号被封的原因&#xf…

《C和指针》笔记13: static关键字总结

这里对static关键字做一下总结&#xff0c;可以回顾一下前面两篇博客的文章。 《C和指针》笔记11: external和internal链接属性 《C和指针》笔记12: 存储类型&#xff08;自动变量、静态变量和寄存器变量&#xff09; 当它用于函数定义时&#xff0c;或用于代码块之外的变量声…

Python Requests模块session的使用建议

本篇主要讲解Python Requests模块session的使用建议及整个会话中的所有cookie的方法。 测试代码 服务端&#xff1a;下面是用flask做的一个服务端&#xff0c;用来设置cookie以及打印请求时的请求头。 # -*- coding: utf-8 -*- from flask import Flask, make_response, req…

3D点云处理:PCL常用数据类型及IO说明

文章目录 1. 常用数据类型1.1 数据类型1.2 有序点云&无序点云2. 数据文件格式3. 数据IO3.1 数据初始化3.2 加载&保存点云(代码)微信:dhlddx B站演示视频 1. 常用数据类型 【PCL中数据类型为float浮点型,需要注意在某些场景下精度是否 满足需求】 1.1 数据类型 既然…

arm:day9

1。思维导图 2..I2C实验&#xff0c;检测温度和湿度 iic.h #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "gpio.h" /* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4…

RabbitMQ默认监听的ip地址

RabbitMQ 默认监听所有可用 ip 地址&#xff0c;当Rabbitmq 所在的服务端节点上存在多 ip 时&#xff0c;只要客户端能与服务端任一 ip 通信&#xff0c;即可向 RabbitMQ 发送消息

SpringBoot实现定时任务操作及cron在线生成器

spring根据定时任务的特征&#xff0c;将定时任务的开发简化到了极致。怎么说呢&#xff1f;要做定时任务总要告诉容器有这功能吧&#xff0c;然后定时执行什么任务直接告诉对应的bean什么时间执行就行了&#xff0c;就这么简单&#xff0c;一起来看怎么做 步骤①&#xff1a;…

统计学补充概念-13-逻辑回归

概念 逻辑回归&#xff08;Logistic Regression&#xff09;实际上是一种用于解决分类问题的统计学习方法&#xff0c;尽管其名称中带有"回归"一词&#xff0c;但它主要用于处理分类任务。逻辑回归用于预测一个事件发生的概率&#xff0c;并将其映射到一个特定的输出…

iPhone 15 Pro与谷歌Pixel 7 Pro:哪款相机手机更好?

考虑到苹果最近将更多高级功能转移到iPhone Pro设备上的趋势,今年秋天iPhone 15 Pro与谷歌Pixel 7 Pro的对决将是一场特别有趣的对决。去年发布的iPhone 14 Pro确实发生了这种情况,有传言称iPhone 15 Pro再次受到了苹果的大部分关注。 预计iPhone 15系列会有一些变化,例如切…

学习笔记:Pytorch利用MNIST数据集训练生成对抗网络(GAN)

2023.8.27 在进行深度学习的进阶的时候&#xff0c;我发了生成对抗网络是一个很神奇的东西&#xff0c;为什么它可以“将一堆随机噪声经过生成器变成一张图片”&#xff0c;特此记录一下学习心得。 一、生成对抗网络百科 2014年&#xff0c;还在蒙特利尔读博士的Ian Goodfello…

Linux操作系统--shell编程(条件判断)

(1).基本的语法 test condition [ condition ] 注意condition前后要有空格;在使用该种表达式的时候,条件非空即为 true,[ hello ]返回 true,[ ] 返回 false。我们可以通过echo $?来判断上一次执行的情况来判断真假(0真1假)。

算法练习- 其他算法练习6

文章目录 数字序列比大小最佳植树距离文艺汇演计算误码率二维伞的雨滴效应 数字序列比大小 A、B两人一人一个整数数组&#xff0c;长度相等&#xff0c;元素随即&#xff1b;两人随便拿出一个元素&#xff08;弹出&#xff09;&#xff0c;比较大小&#xff0c;赢的得一分&…