这样写代码太优雅了吧

news2024/11/17 10:03:30

文章目录

      • 优化案例
      • 初次优化
      • 再次优化
      • 看看Spring源码的处理

优化案例

假设一个场景,

开发代码时,需要对类中的方法进行遍历判断有没有注解@NotNull,暂时没有合适的工具类,需要自己手搓一个。


无须多想,分分钟秒了,我们写出如下的代码很简单,妥妥的满足需求。

    public Boolean hashAnnotation(Class<?> clazz) {
        //为了案例,此处不使用clazz.isAnnotationPresent(annotationClass)
        for (Annotation annotation : clazz.getAnnotations()) {
            if (annotation.annotationType().equals(NotNull.class)) {
                return true;
            }
        }
        return false;
    }

然而,事情不会那么简单,后续发现,还需要判断有没有@NotBlank注解。
这会儿不能再傻傻的单写个判断@NotBlank的方法,于是写下的方法支持所有注解的判断,看上去代码有着那么点拓展性。
在这里插入图片描述

    public Boolean hashAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        //为了案例,此处不使用clazz.isAnnotationPresent(annotationClass)
        for (Annotation annotation : clazz.getAnnotations()) {
            if (annotation.annotationType().equals(annotationClass)) {
                return true;
            }
        }
        return false;
    }

没有什么代码能一蹴而就,意外不期而遇,开发过程中又需要获取类中的所有只有一个参数的方法,和之前获取注解的方法也没法进行复用,只能重新再写一个了。

    public List<Method> isMethodWithSingleParameterOfType(Class<?> clazz) {
        List<Method> methods = new ArrayList<>();
        for (Method method : clazz.getMethods()) {
            if (method.getParameterCount() == 1) {
                methods.add(method);
            }
        }
        return methods;
    }

初次优化

假如后面开发中,还需要对类内部的方法进行处理,难道每次都要依葫芦画瓢写一个新方法吗?
且不说代码的量在不断膨胀,我们经常挂在口上的可拓展性也几乎没有,后续任何的变动,都有可能影响原有的逻辑,除非无脑写新方法。

作为一个合格的Coder,我们要努力的消灭代码中的坏味道。

简单分析上面的几个案例,寻找其中的共性,分离出其中可变化的部分。

需求都需要遍历类中的所有方法

可变的无非是对方法的操作,比如判断方法注解、获取方法的参数等

依据设计原则,封装不变部分拓展可变部分;
不变的部分撑起函数的骨架,再抽象可变部分,稍微一变动,写出如下的代码。增加接口MethodCallback

    public void doWithMethods(Class<?> clazz, MethodCallback mc) {
        Method[] methods = clazz.getMethods();
        /**
         * 封装不变
         */
        for (Method method : methods) {
            mc.doWith(method);
        }
    }

    /**
     * 抽象可变部分
     */
    @FunctionalInterface
    public interface MethodCallback{

        void doWith(Method method);
    }

将可变的方法操作,封装为接口,一者大大提高了方法的复用性,二者是抽象了操作之后对函数的操作也解耦了,不得不说很优雅。

这样优化之后,我们上述的案例都可以改写如下(只是简单展示,并不完善),如果后续有别的个性化的类似需求,只需稳坐钓鱼台,以不变应万变。

再次优化

如果上述案例中再多一个可变的部分,比如说遍历所有方法名称为XXX的注解,
怎么办呢?

依据前面的设计,再次抽象,将过滤再次独立隔离,当做可变部分,增加接口MethodFilter

方法骨架内增加固定逻辑,在方法执行之前,先过滤下方法matches(),支持调用方使用任何的过滤逻辑。


    public void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
        Method[] methods = clazz.getMethods();
        /**
         * 封装不变
         */
        for (Method method : methods) {
            if (!mf.matches(method)) {
                continue;
            }
            mc.doWith(method);
        }
    }

    /**
     * 抽象可变部分
     */
    @FunctionalInterface
    public interface MethodFilter {

        boolean matches(Method method);
    }

看看Spring源码的处理

ReflectionUtils

package org.springframework.util  #ReflectionUtils

骨架方法
在这里插入图片描述

抽象的接口方法
在这里插入图片描述


上述案例即来自Spring的这个代码类,让我觉得尤其惊艳的点,就是对方法行为的封装,MethodCallbackMethodFilter

许多优秀设计中抽象不单单针对是对具象实体,像这种对无法被归成某一类的抽象,让代码更优雅,更值得反复揣摩。
在这里插入图片描述

正如【HeadFirst 设计模式】开篇中的,【组合优先于继承】章节,对duck实体的飞行方式,鸣叫属性的抽象,有异曲同工之妙。

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

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

相关文章

从GPT-3.5到GPT-4O:探索AI的进化之旅,哪一版更懂你?

如何评价GPT-4o? 最新的GPT-4O&#xff0c;被誉为GPT-4的增强版。它在保持前代产品优秀性能的基础上&#xff0c;大幅降低了使用成本&#xff0c;使得更多的普通用户也能享受到顶尖AI的服务。GPT-4O在非英语语言处理上的强化&#xff0c;更是让其在全球范围内的适用性大大提高…

使用Java和XxlCrawler获取各城市月度天气情况实践

目录 前言 一、历史数据获取 1、关于天气后报 2、信息界面分析 二、数据的提取开发 1、PageVo的定义 2、属性定义 3、实际信息抓取 三、信息抓取调试以及可能的问题 1、信息获取成果 2、关于超时的问题 四、总结 前言 这篇文章主要来源于一个我们家小朋友的一个作业…

FreeSwitch视频会议同时支持内网和外网接入

我们在使用freeswitch进行视频会议时&#xff0c;之前所有的用户都是通过外网的方式接入&#xff0c;因为fs给其返回的sdp协议内容里&#xff0c;只需要fs配置的外网IP就可以了&#xff1b;最近由于引入新的业务需要有其他内网的服务器也可以直接接入fs的视频会议房间&#xff…

【Spring Cloud】分布式配置

目录 未来的开发场景为什么需要配置中心配置实时生效配置管理流程 开源配置中心基本介绍DisconfSpring Cloud ConfigApolloNacos Spring Cloud Config介绍配置管理工具体系 案例需求编写 Config Server1.创建配置文件2.创建项目3.添加依赖4.添加注解5.修改配置文件application.…

玩游戏也能学好 JavaScript 啦?

最近有朋友问&#xff0c;应该如何学好 JavaScript。不过我做了好多年的后端开发&#xff0c;JavaScript 虽然也是有所接触&#xff0c;但肯定是谈不上精通。在将朋友介绍给公司的前端大神之后&#xff0c;突然想到&#xff0c;学习编程本身还是一个挺枯燥的事情&#xff0c;如…

FDW(Foreign Data Wrapper)

在上一篇博客里&#xff0c;最末尾提到了 FDW。 FDW 到底是什么呢&#xff1f; 标准 FDW&#xff08;Foreign Data Wrapper&#xff09;遵循了 SQL/MED 标准&#xff0c;标准全称&#xff1a;ISO/IEC 9075-9 Management of External Data (SQL/MED) 2003 年&#xff0c;SQL…

【大数据】Hadoop 2.X和1.X升级优化对比

目录 1.前言 2.hadoop 1.X的缺点和优化方向 3.解决NameNode的局限性 3.1.Hadoop HA 3.2.Haddop federation 4.yarn 5.周边组件 1.前言 本文是作者大数据系列中的一文&#xff0c;专栏地址&#xff1a; https://blog.csdn.net/joker_zjn/category_12631789.html?spm10…

相机系列——相机标定简述

作者&#xff1a;木一 对相机系列感兴趣还可看前文了解更多相关内容&#xff1a; 相机系列——透视投影&#xff1a;针孔相机模型 VR/AR/XR背后的逻辑&#xff1f;离不开三维引擎相机 引言 上文我们介绍了针孔相机模型&#xff0c;用来描述相机的透视投影成像过程&#xf…

数据要素的大海,如何流向千行百业?

文&#xff5c;白 鸽 编&#xff5c;王一粟 当数智化的风吹向银行业&#xff0c;是从底层数据的融合开始的。 在银行风控场景中&#xff0c;一个人想要进行风险投资或借贷&#xff0c;银行往往会评估这个人的信贷和风控策略。在以往的办理模式中&#xff0c;会需要办理人…

看看最新的B端登录界面,你是不是被潮流抛弃了?

毛玻璃风格&#xff08;Frosted Glass Style&#xff09;是新拟态设计风格中的一种分支&#xff0c;它灵感来源于现实世界中的毛玻璃材质。毛玻璃是一种通过在玻璃表面加工处理的方式&#xff0c;使其具有模糊、云翳和透明效果的特殊玻璃。 在设计中&#xff0c;毛玻璃风格通常…

OrangePi Kunpeng Pro体验——安装Hass与驱动SPI小屏幕

OrangePi Kunpeng Pro 是一款面向开发者和爱好者的高性能开发板。在本次测评中&#xff0c;主要将以前的一些代码在该开发板上实现&#xff0c;包括docker部署hass&#xff0c;引脚驱动SPI小屏幕。中间遇到了一些小小问题&#xff0c;但都成功了&#xff0c;一起来试试吧~ 一、…

NoSQL是什么?NoSQL数据库存在SQL注入攻击?

一、NoSQL是什么&#xff1f; NoSQL&#xff08;Not Only SQL&#xff09;是一种非关系型数据库的概念。与传统的关系型数据库不同&#xff0c;NoSQL数据库使用不同的数据模型来存储和检索数据。NOSQL数据库通常更适合处理大规模的非结构化和半结构化数据&#xff0c;且能够…

n后问题 回溯笔记

问题描述 在nn格的棋盘上放置彼此不受攻击的n个皇后。 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同 一行或同一列或同一斜线上的棋子。n后问题等价于在nn格的棋盘上放置n个皇后&#xff0c;任何2个皇后不放在同一行或同一列或同一斜线上。 代码 import java.uti…

史上最全排序算法整理!(1)

1.排序的概念及其应用 1.1排序的概念 排序是计算机内经常进行的一种操作&#xff0c;其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序&#xff0c;若整个排序过程不需要访问外存便能完成&#xff0c;则称此类排序问题为内部排序。反之&#…

linnux上安装php zip(ZipArchive)、libzip扩展

安装顺序&#xff1a; 安装zip&#xff08;ZipArchive&#xff09;&#xff0c;需要先安装libzip扩展 安装libzip&#xff0c;需要先安装cmake 按照cmake、libzip、zip的先后顺序安装 下面的命令都是Linux命令 1、安装cmake 确认是否已安装 cmake --version cmake官网 未安装…

基于k-NN + GCN的轴承故障诊断模型

目录 往期精彩内容&#xff1a; 创新点&#xff1a; 前言 1 轴承故障数据的预处理 1.1 导入数据 1.2 数据预处理&#xff0c;制作数据集 2 基于Pytorch的GCN轴承故障诊断 2.1 定义GCN分类网络模型 2.2 设置参数&#xff0c;训练模型 2.3 模型评估 代码、数据如下&…

乡村振兴与农业科技创新:加大农业科技研发投入,推动农业科技创新,促进农业现代化和美丽乡村建设

一、引言 在当代中国&#xff0c;乡村振兴已成为国家发展的重要战略之一。作为国民经济的基础&#xff0c;农业的发展直接关系到国家的稳定和人民的福祉。随着科技的不断进步&#xff0c;农业科技创新在推动农业现代化和美丽乡村建设中发挥着越来越重要的作用。本文旨在探讨如…

深入理解JVM:内存结构、垃圾收集与性能调优

目录 JDK、JRE、JVM关系? 启动程序如何查看加载了哪些类&#xff0c;以及加载顺序? class字节码文件10个主要组成部分? JVM结构 画一下JVM内存结构图 程序计数器 Java虚拟机栈 本地方法栈 Java堆 方法区 运行时常量池? 什么时候抛出StackOverflowError? 例如&…

SAP_SD模块 物料科目分配/成本简介

SAP系统各模块与财务都有个方面的集成。文本主要说明销售模块中的科目分配和成本的一个对应关系。 1、首先是在物料主数据上销售视图中的物料科目分配组&#xff0c;S1主营、S2材料等字段&#xff0c;物料销售的时候会将这个物料产生的记录到对应的科目中。 首先是物料主数据中…

FreeRTOS【7】队列使用

1.开发背景 操作系统提供了多线程并行的操作&#xff0c;为了方便代码的维护&#xff0c;各个线程都分配了专用的内存并处理对应的内容。但是线程间也是需要协助操作的&#xff0c;例如一个主线程接收信息&#xff0c;会把接收的信息并发到其他线程&#xff0c;即主线程不阻塞&…