0

0

如何在同一类中优化方法间重复逻辑的调用

DDD

DDD

发布时间:2025-08-28 15:52:01

|

579人浏览过

|

来源于php中文网

原创

如何在同一类中优化方法间重复逻辑的调用

本文探讨了在Java项目中,当不同方法中存在重复的代码逻辑时,如何通过重构来提高代码的可维护性和可读性。通过将重复的逻辑封装到一个新的辅助方法中,并将其合理地放置在相关实体类中,可以有效消除代码冗余,遵循DRY(Don't Repeat Yourself)原则,从而优化代码结构和提升开发效率。

一、问题背景与代码冗余分析

在软件开发中,代码复用是提高效率和维护性的关键。然而,在实际项目中,我们经常会遇到不同方法中存在相似或完全相同的代码片段。这种代码冗余不仅增加了维护成本,也使得代码难以阅读和理解。

以下面的Java代码为例,我们有两个方法map和updateUser,它们都涉及从UserEntity中提取RoleEntity的ID并转换为字符串列表的逻辑:

原始map方法:

protected UserDTO map(UserEntity entity) {
    var result = new UserDTO();
    // 重复逻辑片段 A
    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;
}

原始updateUser方法:

public UserResource updateUser(String id, UserResource updatedUser) {
    var optionalUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));
    // 重复逻辑片段 B
    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;
}

显而易见,以下代码片段在两个方法中重复出现:

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

虽然这段代码逻辑不长,但它的重复出现违反了DRY原则。当未来业务需求变化,需要修改角色ID的提取或转换方式时,我们将不得不在多个地方进行修改,这极易引入错误。

二、重构策略:封装重复逻辑到新方法

解决代码冗余最有效的方法是将其抽象为一个独立的、职责单一的方法。尽管有时开发者可能希望避免创建“额外”的方法,但从长远来看,这种封装带来的好处远大于其“额外”的成本。

ColorMagic
ColorMagic

AI调色板生成工具

下载

核心思想: 将重复的逻辑提取出来,封装成一个新的方法。这个新方法应该具有清晰的职责,并且可以被多个调用方复用。

最佳实践:将方法放置在相关实体中 对于上述场景,重复的逻辑是关于从UserEntity中获取其关联的RoleEntity的ID列表。这种操作本质上是UserEntity自身数据的一种派生表示。因此,将这个新方法添加到UserEntity类中,使其成为UserEntity的一个行为,是符合面向对象设计原则(如“告诉,不要询问”)的最佳实践。

1. 创建辅助方法

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

// UserEntity.java
public class UserEntity {
    private Long id;
    private String email;
    private Date lastAccessDate;
    private List<RoleEntity> roles; // 假设RoleEntity包含getId()方法

    // ... 其他属性和方法

    /**
     * 获取用户所有角色的ID列表。
     * @return 包含角色ID字符串的列表。
     */
    public List<String> getRoleIds() {
        if (this.roles == null) {
            return Collections.emptyList(); // 处理roles为null的情况
        }
        return this.roles.stream()
                .map(RoleEntity::getId)
                .map(String::valueOf)
                .collect(Collectors.toList());
    }

    // Getter和Setter方法
    public List<RoleEntity> getRoles() {
        return roles;
    }

    public void setRoles(List<RoleEntity> roles) {
        this.roles = roles;
    }

    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;
    }
}

2. 重构原始方法

现在,我们可以修改map和updateUser方法,用新创建的getRoleIds()方法替换掉重复的逻辑。

重构后的map方法:

protected UserDTO map(UserEntity entity) {
    var result = new UserDTO();
    // 直接调用UserEntity的getRoleIds()方法
    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()));
    if (optionalUser.isPresent()) {
        UserEntity existingUser = optionalUser.get();
        // 直接调用UserEntity的getRoleIds()方法
        updatedUser.setRoles(existingUser.getRoleIds());
        updatedUser.setLastAccessDate(existingUser.getLastAccessDate());
    }
    var entity = mapToUserEntity(updatedUser);
    userRepository.save(entity);
    return updatedUser;
}

三、重构带来的益处与注意事项

通过上述重构,我们获得了以下显著的益处:

  1. 消除代码冗余(DRY原则):重复的逻辑被集中管理,避免了多处修改的风险。
  2. 提高可读性:方法调用entity.getRoleIds()比一长串Stream操作更具表达性,代码意图一目了然。
  3. 增强可维护性:如果角色ID的提取逻辑需要改变(例如,从Long变为UUID,或者需要过滤某些角色),只需修改UserEntity中的getRoleIds()方法一处即可,所有调用方都会自动更新。
  4. 更好的封装性:UserEntity现在负责管理其内部角色ID的表示方式,外部类无需关心其内部实现细节。
  5. 简化测试:getRoleIds()方法可以独立进行单元测试,确保其逻辑的正确性。

注意事项:

  • 命名清晰:新创建的方法名应准确反映其功能,如getRoleIds()清晰地表明了获取角色ID的职责。
  • 处理空值:在getRoleIds()方法中,考虑roles列表为null的情况,返回Collections.emptyList()是一个稳健的做法,避免空指针异常。
  • 职责划分:确保新方法的职责单一。如果一个方法开始承担多个不相关的任务,它可能需要进一步拆分。

四、总结

在软件开发中,面对代码冗余时,积极进行重构是提升代码质量的关键。将重复的逻辑封装到职责单一的辅助方法中,并将其放置在最合适的类中(通常是数据实体类),能够显著提高代码的可读性、可维护性和健壮性。这种看似简单的“额外”方法,实则是遵循面向对象设计原则、构建高质量软件的基石。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

58

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

63

2025.11.27

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1566

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.2万人学习

Java 教程
Java 教程

共578课时 | 80.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号