责任链模式-参数校验

news2024/11/25 3:18:26

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、责任链模式概念
  • 二、责任链模式主要应用场景
  • 三、责任链模式的优点
  • 四、责任链模式的缺点
  • 五、场景案例:参数校验
    • 1.UML图
    • 2.代码实现
      • 2.1.请求体定义
      • 2.2.响应体定义
      • 2.3.数据类型枚举定义
      • 2.4.创建数据校验处理器类
      • 2.5.创建Boolean数据校验处理器
      • 2.6.创建Date数据校验处理器
      • 2.7.创建Integer数据校验处理器
      • 2.8.创建String数据校验处理器
      • 2.9.创建Float数据校验处理器
      • 2.10.创建处理器链
    • 3.单元测试
      • 3.1.类型不匹配
      • 3.2.自定义类型校验
      • 3.3.存在其它未知数据类型
  • 总结


前言

设计模式在工作中的应用之责任链模式

一、责任链模式概念

  • 责任链模式是一种行为设计模式,它将请求的发送者和接收者解耦,将多个处理对象组成一个责任链,并沿着这条责任链依次调用处理对象,直到找到可以处理该请求的对象为止。
  • 在责任链模式中,请求会被依次传递给每一个处理对象,直到其中一个处理对象能够处理该请求或者到达链的末尾。由于每一个处理对象只需要关注自己处理的请求,因此可以有效地分离系统的业务逻辑,增加代码的灵活性和可扩展性。

二、责任链模式主要应用场景

  • 需要动态组合并执行多个业务处理对象的场景
  • 需要对不同类型、级别、优先级或者来源的请求进行分类和处理的场景
  • 有多个对象可以处理同一个请求,但具体由哪个对象处理请求,在运行时才能确定的场景

三、责任链模式的优点

  • 可以有效地将请求发送者和接收者解耦
  • 可以动态添加、删除或者重新排列处理对象
  • 可以灵活地设置处理对象,满足不同类型、级别、优先级或者来源的请求

四、责任链模式的缺点

  • 如果责任链过长,可能会导致请求的传递时间较长,降低系统性能
  • 在责任链中没有明确的指令控制哪个处理对象将会处理请求,且请求会一直传递到责任链末尾,带来一定的不确定性

五、场景案例:参数校验

SpringBoot使用责任链模式校验Map<String,Object>的每一个v是否符合k类型,k的取值有1(字符串)2(布尔类型)3(浮点类型)4(时间类型)...

1.UML图

在这里插入图片描述

2.代码实现

2.1.请求体定义

@Data
@NoArgsConstructor
public class ParamRequest {
    /**
     * 数据类型
     */
    private Integer dataType;

    /**
     * 值
     */
    private Object value;

    // 其它限制条件
    /**
     * 是否必填
     */
    private boolean isRequired;
    /**
     * 单选
     */
    private boolean isSelected;
    /**
     * 多选
     */
    private boolean areSelected;
    /**
     * 最小值
     */
    private String minValue;
    /**
     * 最大值
     */
    private String maxValue;
    /**
     * 备注
     */
    private String remark;

    public ParamRequest(Integer dataType, Object value) {
        this.dataType = dataType;
        this.value = value;
    }

    public ParamRequest(Integer dataType, Object value, boolean isRequired) {
        this.dataType = dataType;
        this.value = value;
        this.isRequired = isRequired;
    }
}

2.2.响应体定义

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;

@ApiModel("响应")
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("编码:0表示成功,其他值表示失败")
    private int code = 0;
    @ApiModelProperty("消息内容")
    private String msg = "success";
    @ApiModelProperty("响应数据")
    private T data;

    public Result() {
    }

    public Result<T> ok(T data) {
        this.setData(data);
        return this;
    }

    public Result<T> okMsg(String msg) {
        this.code = 0;
        this.setMsg(msg);
        return this;
    }

    public boolean success() {
        return this.code == 0;
    }

    public Result<T> error() {
        this.code = 500;
        this.msg = "未知错误";
        return this;
    }

    public Result<T> error(int code) {
        this.code = code;
        this.msg = "未知错误";
        return this;
    }

    public Result<T> error(int code, String msg) {
        this.code = code;
        this.msg = msg;
        return this;
    }

    public Result<T> error(String msg) {
        this.code = 500;
        this.msg = msg;
        return this;
    }

    public Result<T> error(int code, T data) {
        this.code = code;
        this.data = data;
        return this;
    }

    public int getCode() {
        return this.code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return this.msg;
    }

    public Result<T> setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public T getData() {
        return this.data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String toString() {
        return "{\"code\":" + this.code + ",\"msg\":\"" + this.msg + '"' + ",\"data\":" + this.data + "}";
    }
}

2.3.数据类型枚举定义

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author mxf
 * @version 1.0
 * @description: 数据类型枚举
 * @date 2023/5/23
 */
@Getter
@AllArgsConstructor
public enum DataTypeEnum {

    /**
     * 布尔类型
     */
    BOOLEAN(1, Boolean.class),
    /**
     * 日期类型
     */
    DATE(2, Date.class),
    /**
     * 浮点类型
     */
    FLOAT(3, Float.class),
    /**
     * 字符串类型
     */
    STRING(4, String.class),
    /**
     * 整值类型
     */
    INTEGER(5, Integer.class);
    final static Set<Integer> DATA_TYPE_ENUM_CODE_SET;
    final static List<DataTypeEnum> DATA_TYPE_ENUM_LIST;

    static {
        DATA_TYPE_ENUM_CODE_SET = Arrays.stream(DataTypeEnum.values())
                .map(DataTypeEnum::getCode)
                .collect(Collectors.toSet());

        DATA_TYPE_ENUM_LIST = Arrays.stream(DataTypeEnum.values()).collect(Collectors.toList());
    }

    /**
     * code
     */
    private final Integer code;
    /**
     * 参数类型
     * /
    private final Class<?> clazz;

    public static boolean exitByCode(Integer code) {
        return DATA_TYPE_ENUM_CODE_SET.contains(code);
    }

    public static Class<?> getClazzByCode(Integer code) {
        return DATA_TYPE_ENUM_LIST.stream().filter(dte -> dte.getCode().equals(code)).map(DataTypeEnum::getClazz).findFirst().orElse(null);
    }
}

2.4.创建数据校验处理器类

斜体样式用于校验数据类型

import com.alibaba.fastjson.JSON;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;

/**
 * @author 28382
 */
public abstract class DataValidHandler<T> {

    protected DataValidHandler next;


    /**
     * 用于对下一个处理器的引用
     */
    public void setNext(DataValidHandler next) {
        this.next = next;
    }

    /**
     * 其它规则校验
     */
    public Result<Void> ruleVerification(String key, ParamRequest paramRequest) {
        // 默认实现
        return new Result<>();
    }

    private Class<?> getClazz() {
        // 使用反射获取 DataValidHandler 类中声明的泛型类型参数
        Type parameterizedType = this.getClass().getGenericSuperclass();
        return (Class<?>) ((ParameterizedType) parameterizedType).getActualTypeArguments()[0];
    }

    /**
     * 处理
     */
    public final Result<Void> handle(Map<String, ParamRequest> paramMap) {
        Iterator<Map.Entry<String, ParamRequest>> iterator = paramMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, ParamRequest> entry = iterator.next();
            ParamRequest paramRequest = entry.getValue();
            if (Objects.isNull(paramRequest) || (getClazz() != DataTypeEnum.getClazzByCode(paramRequest.getDataType()))) {
                continue;
            }
            if (paramRequest.getValue() != null && !getClazz().isInstance(paramRequest.getValue())) {
                paramMap.clear();
                next = null;
                return new Result<Void>().error("Value of " + entry.getKey() + " is invalid: " + paramRequest.getValue());
            }
            Result<Void> ruleVerificationResult = ruleVerification(entry.getKey(), paramRequest);
            if (ruleVerificationResult.getCode() != 0) {
                paramMap.clear();
                next = null;
                return ruleVerificationResult;
            }
            iterator.remove();
        }

        return nextHandle(paramMap);
    }

    /**
     * @param paramMap 参数列表
     * @return com.mxf.code.chain_params.Result<java.lang.Void>
     * @author mxf
     * @description 下一个处理器
     * @createTime 2023/5/24 10:46
     * @paramType [java.util.Map<java.lang.String, com.mxf.code.chain_params.ParamRequest>]
     */
    public final Result<Void> nextHandle(Map<String, ParamRequest> paramMap) {
        Result<Void> handleResult = new Result<>();
        if (!Objects.isNull(next)) {
            handleResult = next.handle(paramMap);
        } else {
            if (!CollectionUtils.isEmpty(paramMap)) {
                return new Result<Void>().error("存在其它类型参数未被校验:" + JSON.toJSONString(paramMap));
            }
        }
        return handleResult;
    }
}

2.5.创建Boolean数据校验处理器

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @author 28382
 */
@Component
@Order(0)
public class BooleanValidHandler extends DataValidHandler<Boolean> {
    @Override
    public Result<Void> ruleVerification(String key, ParamRequest paramRequest) {
        // 判断是否必填
        boolean isRequired = paramRequest.isRequired();
        if (isRequired && Objects.isNull(paramRequest.getValue())) {
            return new Result<Void>().error("Value of " + key + " is required");
        }
        return new Result<>();
    }
}

2.6.创建Date数据校验处理器

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author 28382
 */
@Component
@Order(1)
public class DateValidHandler extends DataValidHandler<Date> {
	// 可重写ruleVerification()
}

2.7.创建Integer数据校验处理器

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author 28382
 */
@Component
@Order(2)
public class IntegerValidHandler extends DataValidHandler<Integer> {

}

2.8.创建String数据校验处理器

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author 28382
 */
@Component
@Order(3)
public class StringValidHandler extends DataValidHandler<String> {

}

2.9.创建Float数据校验处理器

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author 28382
 */
@Component
@Order(4)
public class FloatValidHandler extends DataValidHandler<Float> {

}

2.10.创建处理器链

该类使用SpringBoot提供的@Autowired注解注入所有实现了DataValidHandler接口的Bean,并按照Order注解指定的顺序对处理器链进行排序,最后将所有处理器串联起来。同时,该类也提供一个handle()方法,用于启动数据的处理。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author 28382
 */
@Service
public class DataValidHandlerChain {

    // 自动注入
    @Autowired
    private List<DataValidHandler> handlers;

    /**
     * 创建数据验证责任链
     */
    @PostConstruct
    public void init() {
        handlers.sort(Comparator.comparingInt(h -> getOrder(h.getClass())));
        for (int i = 0; i < handlers.size() - 1; i++) {
            handlers.get(i).setNext(handlers.get(i + 1));
        }
    }

    private int getOrder(Class<?> clazz) {
        Order order = clazz.getDeclaredAnnotation(Order.class);
        return (order != null) ? order.value() : Ordered.LOWEST_PRECEDENCE;
    }

    /**
     * 开始处理数据
     */
    public Result<Void> handle(Map<String, ParamRequest> data) {
        return handlers.get(0).handle(data);
    }
}

3.单元测试

3.1.类型不匹配

import com.mxf.code.chain_params.DataTypeEnum;
import com.mxf.code.chain_params.DataValidHandlerChain;
import com.mxf.code.chain_params.ParamRequest;
import com.mxf.code.chain_params.Result;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class ChainTest {

    @Autowired
    private DataValidHandlerChain handlerChain;

    @Test
    public void test01() {
        Map<String, ParamRequest> data = new HashMap<>();
        data.put("name", new ParamRequest(DataTypeEnum.STRING.getCode(), 1));
        Result<Void> handle = handlerChain.handle(data);
        log.info("handle = {}", handle);
    }
}

在这里插入图片描述

3.2.自定义类型校验

布尔类型不能为空

@Test
public void test02() {
    Map<String, ParamRequest> data = new HashMap<>();
    data.put("male", new ParamRequest(DataTypeEnum.BOOLEAN.getCode(), null, true));
    Result<Void> handle = handlerChain.handle(data);
    log.info("handle = {}", handle);
}

在这里插入图片描述

3.3.存在其它未知数据类型

@Test
public void test03() {
     Map<String, ParamRequest> data = new HashMap<>();
     data.put("subordinate",new ParamRequest(null,""));
     Result<Void> handle = handlerChain.handle(data);
     log.info("handle = {}", handle);
 }

在这里插入图片描述

总结

使用该方式可应用于动态传参的场景,判断值是否符合预期数据类型及自定义校验规则

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

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

相关文章

【信号变化检测】使用新颖的短时间条件局部峰值速率特征进行信号变化/事件/异常检测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

day16 - 提取图像前景

在我们平时使用购物软件是会发现通常在搜索框右侧都会有一个相机的标志&#xff0c;这个标志是可以让用户通过图片来搜索自己需要购买的内容。拍照购物将用户拍摄的商品与商品图库的图像进行对比&#xff0c;找到最为相似的商品。但是由于用户拍摄的图像是任意的随机的&#xf…

使用Arcgis免费获取全国地质数据

使用Arcgis免费使用全国地质数据 如今是大数据并发的时代&#xff0c;并且还是数据大开放的时代。全国地质资料馆开放了大量的地质资料数据&#xff0c;供全民使用。今天我在这里教大家使用免费的数据&#xff0c;帮助我们工作。 全国地质资料馆地址&#xff1a; http://www.ng…

基于广义Benders分解法的综合能源系统优化规划(matlab程序)

目录 1 主要内容 广义benders分解法流程图&#xff1a; 优化目标&#xff1a; 约束条件&#xff1a; 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现文章《综合能源系统协同运行策略与规划研究》第四章内容基于广义Benders分解法的综合能源系统优化规划&…

图学习 [1]

图学习 [1] 图学习的主要任务 节点预测。节点预测任务是指利用图结构中已有的节点和边信息&#xff0c;通过机器学习算法对图中新添加的节点进行分类或回归预测的任务。链路预测。链路预测任务是指利用图结构中已有的节点和边信息&#xff0c;通过机器学习算法预测未来可能存…

【C++初阶】友元 + 内部类 + 匿名对象

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

欢迎所有用户! Elastic 扩展知识中心和支持中心

作者&#xff1a;Cory Mangini 对于所有云用户&#xff0c;我们有一些好消息&#xff1a;你现在可以访问我们的知识中心&#xff0c;在云试用期间请求技术支持&#xff0c;并通过 Elastic Support Hub 提出账单案例。 这意味着你可以利用我们的 Elasticians 多年来积累的丰富知…

基于html+css的图展示90

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

day20 - 绘制物体的运动轨迹

在我们平常做目标检测或者目标追踪时&#xff0c;经常要画出目标的轨迹图。绘制轨迹图的一种方法就是利用光流估计来进行绘制。 本期我们主要来介绍视频中光流估计的使用和效果&#xff0c;利用光流估计来绘制运动轨迹。 完成本期内容&#xff0c;你可以&#xff1a; 掌握视…

通过js来判断是否是横屏如果是就自刷新页面解决横屏之后只有屏幕一半宽度的问题

判断页面是横屏还是竖屏 window.addEventListener("load", rotate, false);window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", rotate, false);function rotate() {if (window.orientatio…

首个机器学习实时特征平台测试基准论文被 VLDB 2023 录取

国际顶级数据库学术会议 VLDB 2023 将于 2023 年 8 月份在加拿大温哥华举办。近日&#xff0c;由清华大学、新加坡国立大学、以及 OpenMLDB 社区联合完成的科研成果 - 业界第一个严谨的机器学习实时特征平台测试基准&#xff0c;被大会录取并且受邀在现场报告。论文题目为&…

Mybatis-动态SQL

1.什么是动态SQL? Mabits是一个Java持久化框架&#xff0c;它提供了动态SQL的功能。动态SQL是一种根据不同条件动态生成SQL语句的技术。在Mabits中&#xff0c;动态SQL通常是通过使用一组特殊的标签和代码块来实现的&#xff0c;这些标签和代码块可以根据条件包含或排…

性能测试——jmeter实时压测结果收集

这里写目录标题 前言一、压测监控平台组成二、性能监控平台部署 - InfluxDB三、性能监控平台部署 - JMeter四、性能监控平台部署 - Grafana五、性能监控平台部署 – 运行与结果展示 前言 测试报告 .vs. 压测监控 JMeter原生测试报告带来的“痛苦” • 不具备实时性 • 报告中的…

单体项目偶遇并发漏洞!短短一夜时间竟让老板蒸发197.83元

事先声明&#xff1a;以下故事基于真实事件而改编&#xff0c;如有雷同&#xff0c;纯属巧合~ 眼下这位正襟危坐的男子&#xff0c;名为小竹&#xff0c;他正是本次事件的主人公&#xff0c;也即将成为熊猫集团的被告&#xff0c;嗯&#xff1f;这究竟怎么一回事&#xff1f;欲…

通过白噪声的频谱处理产生任意光谱斜率(f^a)噪声(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

首站中科院!百度商业AI技术创新大赛开启巡回宣讲

近日&#xff0c;百度商业AI技术创新大赛正式启动&#xff0c;并于5月18日起开启高校巡回宣讲。 宣讲会首站落地中国科学院大学&#xff0c;中国科学院大学人工智能学院副院长、教授、博士生导师肖俊教授&#xff0c;百度商业研发主任架构师焦学武&#xff0c;百度商业资深工程…

springboot 集成 Swagger3(速通)

→ springboot 集成 Swagger2 ← 目录 1. 案例2. info 配置3. Docket 配置1. 开关配置2. 扫描路径3. 路径匹配4. 分组管理 4. 常用注解1. 说明2. 案例 1. 案例 这次直接使用 2.5.6 的 spring-boot 。 依赖&#xff1a; <parent><groupId>org.springframework.…

亏损?盈利?禾赛科技Q1财报背后的激光雷达赛道「现实」

随着禾赛科技在去年登陆美股&#xff0c;作为全球为数不多已经开始前装量产交付的激光雷达上市公司&#xff0c;财务数据的变化&#xff0c;也在一定程度上反映了行业的真实状况。 根据禾赛科技最新发布的今年一季度财报显示&#xff0c;公司季度净营收为4.3亿元&#xff08;人…

基于html+css的图展示91

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

电表及配电监控系统的智能化发展

安科瑞虞佳豪 在电力领域&#xff0c;AI渗透率近年来也持续提升。今年3月&#xff0c;国家能源局发布《关于加快推进能源数字化智能化发展的若干意见》&#xff0c;文件中针对电力、、油气等行业数字化智能化转型&#xff0c;明确了指导思想和基本原则&#xff0c;从加快行业转…