Java代码重构实践:通过方法提取消除重复逻辑

Java代码重构实践:通过方法提取消除重复逻辑

本教程深入探讨在Java开发中,如何通过将重复的业务逻辑封装为独立方法来有效消除代码冗余,从而提升代码的可维护性和可读性。针对跨多个方法共享的特定逻辑片段,我们将演示如何将其提取并集成到相关实体类中,例如在 UserEntity 中添加 getRoleIds() 方法,以实现代码的精简与高效复用,同时增强领域模型的表达能力。

1. 问题背景与代码冗余分析

在软件开发过程中,代码冗余是一个常见且亟待解决的问题。当同一段逻辑出现在应用程序的不同方法中时,不仅增加了代码量,更重要的是降低了代码的可维护性、可读性,并增加了引入缺陷的风险。例如,当业务规则发生变化时,开发者需要修改所有包含该重复逻辑的地方,这极易遗漏或引入不一致性。

考虑以下Java代码示例,其中 map 方法用于将 UserEntity 转换为 UserDTO,而 updateUser 方法则处理用户更新逻辑:

原始代码片段:

// 方法一:mapprotected UserDTO map(UserEntity entity) {    var result = new UserDTO();    // 存在重复逻辑    var userRoles = entity.getRoles().stream()            .map(RoleEntity::getId)            .map(String::valueOf)            .collect(Collectors.toList());    result.setId(entity.getId().toString());    result.setLastAccessDate(entity.getLastAccessDate());    result.setRoles(userRoles);    if (entity.getEmail() != null) {        var email = new UserDTO.Email(entity.getEmail(), EMAIL_TYPE);        result.setEmails(List.of(email));    }    return result;}// 方法二:updateUserpublic UserResource updateUser(String id, UserResource updatedUser) {    var optionalUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));    // 存在重复逻辑    updatedUser.setRoles(optionalUser.get().getRoles()            .stream()            .map(RoleEntity::getId)            .map(String::valueOf)            .collect(Collectors.toList()));    updatedUser.setLastAccessDate(optionalUser.get().getLastAccessDate());    var entity = mapToUserEntity(updatedUser);    userRepository.save(entity);    return updatedUser;}

在这两个方法中,提取用户角色ID列表的逻辑完全相同:

.getRoles().stream().map(RoleEntity::getId).map(String::valueOf).collect(Collectors.toList())

这种重复不仅使得代码难以阅读,也使得未来对角色ID提取逻辑的任何修改都必须在两个地方进行,增加了出错的可能性。

立即学习“Java免费学习笔记(深入)”;

2. 解决方案:提取方法(Extract Method)

解决代码冗余最有效且最常用的策略之一是“提取方法”(Extract Method)重构技术。其核心思想是将一段重复的或具有独立逻辑的代码块封装成一个新的方法,然后在原有的位置调用这个新方法。

针对上述问题,最佳实践是将提取角色ID列表的逻辑封装到 UserEntity 类自身的一个新方法中。这样做有以下几个优点:

增强领域模型: UserEntity 作为领域对象,拥有获取其角色ID列表的能力是符合其职责的,这使得实体更加“智能”和自洽。提高内聚性: 将与 UserEntity 相关的操作放在 UserEntity 类中,符合高内聚的设计原则。简化调用: 调用方无需了解角色ID提取的具体实现细节,只需调用一个语义明确的方法即可。

2.1 改造 UserEntity 类

首先,在 UserEntity 类中添加一个名为 getRoleIds() 的新方法,用于封装提取角色ID的逻辑。

// 假设这是您的 UserEntity 类public class UserEntity {    private Long id;    private String email;    private Date lastAccessDate;    private List roles; // 假设 RoleEntity 包含 getId() 方法    // ... 其他属性和方法    /**     * 获取用户所有角色的ID列表。     * @return 包含角色ID字符串的列表。     */    public List getRoleIds() {        if (this.roles == null || this.roles.isEmpty()) {            return Collections.emptyList();        }        return this.roles.stream()                .map(RoleEntity::getId)                .map(String::valueOf)                .collect(Collectors.toList());    }    // Getter和Setter方法    public Long getId() { return id; }    public void setId(Long id) { this.id = id; }    public String getEmail() { return email; }    public void setEmail(String email) { this.email = email; }    public Date getLastAccessDate() { return lastAccessDate; }    public void setLastAccessDate(Date lastAccessDate) { this.lastAccessDate = lastAccessDate; }    public List getRoles() { return roles; }    public void setRoles(List roles) { this.roles = roles; }}// 假设 RoleEntity 类class RoleEntity {    private Long id;    private String name;    public RoleEntity(Long id, String name) {        this.id = id;        this.name = name;    }    public Long getId() { return id; }    public void setId(Long id) { this.id = id; }    public String getName() { return name; }    public void setName(String name) { this.name = name; }}

2.2 重构调用方方法

一旦 UserEntity 拥有了 getRoleIds() 方法,我们就可以在原先存在重复逻辑的地方直接调用它,从而大大简化代码。

重构后的 map 方法:

protected UserDTO map(UserEntity entity) {    var result = new UserDTO();    // 调用 UserEntity 的新方法    var userRoles = entity.getRoleIds();    result.setId(entity.getId().toString());    result.setLastAccessDate(entity.getLastAccessDate());    result.setRoles(userRoles);    if (entity.getEmail() != null) {        var email = new UserDTO.Email(entity.getEmail(), EMAIL_TYPE);        result.setEmails(List.of(email));    }    return result;}

重构后的 updateUser 方法:

public UserResource updateUser(String id, UserResource updatedUser) {    var optionalUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));    // 调用 UserEntity 的新方法    updatedUser.setRoles(optionalUser.get().getRoleIds());    updatedUser.setLastAccessDate(optionalUser.get().getLastAccessDate());    var entity = mapToUserEntity(updatedUser);    userRepository.save(entity);    return updatedUser;}

通过这种方式,原本冗长的流式操作被一个简洁、语义明确的方法调用所取代,代码变得更加清晰和易于维护。

3. 注意事项与最佳实践

在进行方法提取重构时,需要考虑以下几点以确保重构的质量和有效性:

方法命名: 新方法的名称应清晰、准确地表达其功能和意图。例如,getRoleIds() 明确表示获取角色ID列表。方法可见性: 根据新方法的职责和调用范围,合理设置其可见性(public, protected, private)。如果它只在类内部使用,则应设为 private。在本例中,由于 getRoleIds() 可能被其他外部类(如服务层或DTO转换逻辑)调用,public 是合适的选择。参数设计: 如果被提取的逻辑需要外部数据,应将这些数据作为参数传递给新方法。本例中,getRoleIds() 直接操作 UserEntity 自身的 roles 属性,无需额外参数。无副作用原则: 尽量确保提取的方法是“纯函数”,即不修改其外部状态,只根据输入产生输出。如果必须有副作用,应明确文档说明。测试覆盖: 在进行任何重构之前,确保有充分的单元测试覆盖。重构后,运行这些测试以验证功能的正确性未受影响。粒度适中: 提取的方法不宜过大也不宜过小。过大可能包含多种职责,过小则可能引入过多方法调用开销且无明显收益。本例中提取的逻辑粒度适中,专注于一个单一的职责。

4. 总结

代码重构是软件开发中不可或缺的一部分,它有助于提升代码质量、降低维护成本。本文通过一个具体的Java代码冗余示例,演示了如何运用“提取方法”这一核心重构技术,将重复逻辑封装到领域实体类中。这种做法不仅有效地消除了代码冗余,还增强了领域模型的表达能力和代码的可读性。遵循这些最佳实践,开发者可以构建出更健壮、更易于管理和扩展的应用程序。

以上就是Java代码重构实践:通过方法提取消除重复逻辑的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/96911.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
win10打开exe文件没反应 win10双击exe可执行文件无反应的修复技巧
上一篇 2025年11月20日 01:24:20
SSD 从高效存储走到失效边缘 你需知道的几大警示信号
下一篇 2025年11月20日 01:26:22

相关推荐

  • 谷歌浏览器官方在线访问 最新版Chrome官网登录

    谷歌浏览器官方在线访问入口是https://www.google.cn/chrome/,提供简洁界面、跨设备同步、高效内核、安全防护和丰富扩展生态。 谷歌浏览器官方在线访问入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来最新版Chrome官网登录地址,想要获取纯净浏览体验的网友一起随小…

    2026年9月21日
    100
  • Java Collections.singletonList如何创建单元素集合

    Collections.singletonList(T item) 返回只含一个元素的不可变列表,传入指定对象后生成轻量级只读集合,适用于需高效传递单元素场景。该列表禁止修改操作,否则抛出异常,允许 null 元素,内部优化减少内存开销,常用于 API 参数传递或流处理中的临时数据构造。 Java …

    2026年9月21日
    000
  • JavaScript中的模块联邦如何实现微前端的代码共享?

    模块联邦通过运行时动态加载实现微前端代码共享,无需打包公共依赖。使用 ModuleFederationPlugin 配置 name、remotes、exposes 和 shared,使应用可暴露或引入远程模块,支持组件、工具函数及状态管理共享,提升复用性并减少冗余。 模块联邦通过在构建时让不同应用直…

    2026年9月21日
    200
  • Swoole如何实现一个UDP服务器

    答案:使用Swoole可轻松创建高性能UDP服务器。通过new SwooleServer()设置UDP套接字,监听Packet事件接收数据,利用sendto()回复客户端;结合set()配置worker_num等参数优化性能,配合PHP UDP客户端测试通信,适用于高并发、低延迟场景。 使用Swoo…

    2026年9月21日
    000
  • MySQL执行计划中的Extra字段代表什么_怎么看优化空间?

    MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?

    在 mysql 查询优化中,执行计划的 extra 字段用于说明查询执行时的额外操作,常见的值包括:1. using filesort 表示需要额外排序,应尽量通过建立索引避免;2. using temporary 表示使用了临时表,常见于 group by 或复杂 join,需优化减少其使用;3.…

    2026年9月21日 用户投稿
    000
  • 如何通过tracert命令追踪数据包从本地到目标服务器的完整路径?

    打开命令提示符,输入cmd并回车;2. 执行tracert 目标地址命令追踪路径;3. 查看每跳响应时间与IP,分析延迟变化定位网络瓶颈;4. 注意部分节点可能因防火墙不响应导致超时。 使用 tracert(Windows 系统)命令可以追踪数据包从你的计算机到目标服务器所经过的每一跳网络节点,帮助…

    2026年9月21日
    900
  • PHP简易路由框架构建:从URL解析到动态控制器加载的实践指南

    本文旨在指导读者构建一个基础的PHP路由系统,实现URL路径到控制器方法的高效映射。内容涵盖URL解析、控制器动态加载、方法调用以及关键的错误处理机制,特别强调如何避免常见的“未定义变量”错误和文件包含路径问题,确保路由系统稳定且易于维护。 一、路由系统核心原理 构建一个简单的php路由系统,其核心…

    2026年9月21日
    100
  • 如何在Java中理解Java I/O与NIO机制

    传统I/O是阻塞式流模型,适用于低并发场景;NIO基于缓冲区与通道,支持非阻塞和多路复用,适合高并发网络应用,核心区别在于线程模型与资源利用率。 Java中的I/O(输入/输出)与NIO(New I/O)是处理数据读写的核心机制,理解它们的区别和使用场景对开发高性能应用至关重要。传统I/O基于流模型…

    2026年9月21日
    100
  • UC浏览器网页上的文字无法选中复制怎么办 UC浏览器解决网页文字禁止复制问题

    答案:可通过开发者工具、阅读模式、打印预览、OCR识别或自定义脚本解除UC浏览器网页复制限制。具体操作依次为:开启开发者工具并执行JavaScript代码解除限制;启用阅读模式净化页面内容;使用打印预览重新渲染页面以选中文字;对截图应用OCR技术提取文本;添加书签脚本自动移除禁用选择的代码,从而实现…

    2026年9月21日
    100
  • JavaScript中的尾调用优化(TCO)在ES6中如何工作?

    尾调用是指函数的最后一个动作调用另一个函数,ES6引入尾调用优化以重用栈帧、避免内存溢出,支持真正的尾递归,如阶乘函数通过累积参数实现。 尾调用优化(Tail Call Optimization, TCO)是ES6引入的一项语言特性,目的是在特定条件下重用函数调用栈帧,避免不必要的内存增长,从而支持…

    2026年9月21日
    200
  • 抖音蝴蝶号无人直播带货操作流程及注意事项

    抖音蝴蝶号无人直播带货操作流程及注意事项抖音蝴蝶号无人直播带货操作流程及注意事项抖音蝴蝶号无人直播带货操作流程及注意事项抖音蝴蝶号无人直播带货操作流程及注意事项

    “抖音蝴蝶号无人直播带货”是一种通过自动化或半自动化技术实现的直播销售模式。①其核心在于摆脱真人主播限制,实现24小时不间断直播,提升效率与流量利用率;②关键步骤包括明确账号定位与商品选择、准备高质量且丰富的内容素材、利用虚拟人或预录内容实现直播推流、结合智能客服模拟评论区互动;③优势在于降低人力成…

    2026年9月21日 用户投稿
    500
  • Java语法基础有哪些新手必学的核心知识

    掌握Java基本数据类型与变量声明,如int、double、char和boolean,并理解强类型语言特性;2. 熟悉运算符与表达式,包括算术、比较和逻辑运算符,奠定程序逻辑基础。 Java语法基础是每个初学者必须掌握的内容,只有打好根基,才能顺利进阶面向对象编程和实际项目开发。以下是新手必学的核心…

    2026年9月21日
    300
  • 音乐文件占用空间太多怎么办_音乐文件占用空间太多如何整理详细指南

    解决音乐文件占空间问题的关键是压缩与整理:先用软件或在线工具降低比特率压缩体积,再按场景分类、利用元数据自动归集,并通过听歌片段和BPM判断保留内容,避免重复与误删。 音乐文件占空间太多,核心解决办法就两条:一是压缩单个文件体积,二是通过有效分类管理提升使用效率。直接删歌不是长久之计,学会整理和优化…

    2026年9月21日
    000
  • 升级X86架构性能大提升!极空间Z2 Ultra图赏

    升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏升级X86架构性能大提升!极空间Z2 Ultra图赏

    10月23日,极空间正式推出全新双盘位nas产品——极空间z2 ultra,官方售价为1899元,参与国家补贴后仅需1457元,性价比进一步提升。 此次发布的Z2 Ultra最大的亮点在于采用X86架构处理器,相较以往使用的ARM平台,性能实现飞跃式提升,运行速度显著加快。更重要的是,新架构对Doc…

    2026年9月21日 用户投稿
    300
  • 数据库分库分表(Sharding)策略

    在现代应用程序中,随着数据量的增长,单一数据库的性能和容量往往难以满足需求。这时,数据库分库分表(Sharding)策略就成了一个关键的解决方案。那么,如何设计和实现一个有效的分库分表策略呢?让我们深入探讨一下。 在我的职业生涯中,我曾多次参与大型项目的数据库优化,其中分库分表是常见的挑战之一。我记…

    2026年9月21日
    000
  • 如何在Java中实现个人财务管理工具

    首先设计Transaction、FinanceManager和Budget核心类,实现交易记录、统计分析与预算控制功能,通过ArrayList管理数据,使用LocalDate处理日期,结合ObjectOutputStream持久化存储,初期采用Scanner构建控制台菜单实现增删查改与报表展示,后期…

    2026年9月21日
    100
  • X旗下Grok上线即时语音搜索,挑战Google引领搜索新方向

    近日,x平台旗下的ai助手grok正式推出了“即时语音搜索”功能。用户现在可以通过语音直接提问,触发实时网页检索,并迅速获得整合后的精准答案。此举意在优化信息获取流程,推动人机交互向更自然、高效的方向演进。 该语音搜索模式实现了“即说即搜即答”的流畅体验。例如,当用户提出“星舰发射的具体时间是什么?…

    2026年9月21日
    100
  • Laravel应用的安全审计(Security Audit)方法

    进行安全审计对laravel应用至关重要,因为它能发现并修复安全漏洞,提升整体安全性和用户信任度。具体方法包括:1. 代码审查,确保无未过滤输入和弱密码;2. 配置文件安全性,保护敏感信息;3. 依赖管理,更新第三方包;4. 用户认证和授权,防止未授权访问;5. 日志和监控,检测异常行为。 在讨论L…

    2026年9月21日
    100
  • Laravel 8 登录后重定向到仪表盘的全面指南

    本文深入探讨了 Laravel 8 中用户登录后重定向到仪表盘的多种策略。我们将详细解析默认的重定向机制,包括 LoginController 和 RedirectIfAuthenticated 中间件,并重点介绍如何通过自定义登录逻辑实现精确的重定向控制,同时提供示例代码和常见问题排查建议,确保用…

    2026年9月21日
    000
  • Guava Multimap:高效获取并打印指定键的所有关联值

    guava multimap是处理一键多值映射关系的强大工具。要获取特定键的所有关联值,应直接使用其提供的`multimap#get(k)`方法。该方法会返回一个包含所有匹配值的`collection`,即使键不存在,也会返回一个空集合而非`null`,从而简化了值检索和空值处理逻辑,是比手动迭代键…

    2026年9月21日
    100

发表回复

登录后才能评论
关注微信