讲师中心 微信公众号
AI工具推荐 视频效率加速

Java代码重构:通过实体类方法封装重复逻辑提升代码复用性

雨芳君_5905

雨芳君_5905

发布时间:2025-08-28 15:46:22

|

574人浏览过

|

来源于php中文网

原创

Java代码重构:通过实体类方法封装重复逻辑提升代码复用性

本教程旨在解决Java开发中常见的代码重复问题,特别是当多个方法需要对同一实体类(如UserEntity)的集合属性(如角色列表)执行相同的数据转换逻辑时。核心策略是将重复的转换逻辑封装成实体类内部的一个新方法,从而提高代码的可维护性和复用性,避免在不同业务方法中复制代码块。

问题剖析:业务方法中的代码重复

在复杂的业务系统中,我们经常会遇到需要在不同服务或映射方法中对同一实体对象进行相同的数据处理或转换。例如,在将userentity对象转换为userdto或更新userresource时,可能都需要提取userentity中roles集合的id,并将其转换为string类型的列表。

考虑以下两个示例方法:

原始 map 方法: 该方法负责将 UserEntity 映射到 UserDTO。

import java.util.List;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.Optional; // For userRepository.findById later

// 假设 UserDTO, UserEntity, RoleEntity, UserResource, UserRepository 已定义
// 以及常量 EMAIL_TYPE

public class UserService { // 示例服务类

    private static final String EMAIL_TYPE = "PRIMARY"; // 示例常量

    protected 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); // 使用转换后的角色ID列表
        if (entity.getEmail() != null) {
            var email = new UserDTO.Email(entity.getEmail(), EMAIL_TYPE);
            result.setEmails(List.of(email));
        }
        return result;
    }

    // ... 其他方法 ...
}

原始 updateUser 方法: 该方法负责更新用户资源,其中也包含对角色ID的相同处理。

import java.util.List;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.Optional;

// 假设 UserDTO, UserEntity, RoleEntity, UserResource, UserRepository 已定义

public class UserService { // 示例服务类

    private UserRepository userRepository; // 假设已通过构造函数或注解注入

    // 假设 mapToUserEntity 方法已定义
    private UserEntity mapToUserEntity(UserResource updatedUser) {
        // 实际的映射逻辑,这里仅作示例
        UserEntity entity = new UserEntity();
        entity.setId(Integer.valueOf(updatedUser.getUserName())); // 假设 userName 是 ID
        entity.setLastAccessDate(updatedUser.getLastAccessDate());
        // 角色设置可能需要从 updatedUser.getRoles() 映射回 RoleEntity
        // 这里为了演示简化,只关注从 optionalUser.get() 获取角色
        return entity;
    }

    public UserResource updateUser(String id, UserResource updatedUser) {
        var optionalUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));
        if (optionalUser.isEmpty()) {
            // 处理用户不存在的情况,例如抛出异常
            throw new IllegalArgumentException("User not found with ID: " + 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); // 将 UserResource 映射回 UserEntity
        userRepository.save(entity); // 保存更新后的实体
        return updatedUser;
    }

    // ... 其他方法 ...
}

可以看到,以下代码片段在两个方法中完全重复:

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

这种重复不仅增加了代码量,更重要的是降低了可维护性。一旦角色ID的提取逻辑需要修改(例如,从Integer变为Long,或者需要额外的过滤),就必须同时修改所有出现该逻辑的地方,这极易出错且效率低下。

解决方案:将领域逻辑封装至实体类

为了消除这种重复并提高代码的内聚性,最佳实践是将这种与实体自身数据紧密相关的转换逻辑封装到实体类内部。这意味着UserEntity应该“知道”如何提供其角色ID的列表,而不是让外部方法每次都重新计算。

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

实现步骤与示例

  1. 在 UserEntity 中添加新方法

    Java调试
    Java调试

    通过 JDWP 实现 Java 远程调试:连接远程 JVM、设置断点、单步执行代码、查看变量值、获取调用栈。适用于需要调试远程 Java 应用、排查运行时状态、追踪代码执行流程的场景。 术语注解 JDWP:Java Debug Wire Protocol,Java 调试有线协议(Java 远程调试底层通信协议) remote JVM:远程 Java 虚拟机 step through code:代码单步调试(步入 / 步过 / 步出调试) inspect variables:变量查看 / 变量检视 stac

    下载

    我们将创建一个名为getRoleIds()的新方法,将其添加到UserEntity类中。该方法将负责执行原先重复的流式操作,并返回一个List。

    import java.util.List;
    import java.util.Date;
    import java.util.Collections;
    import java.util.stream.Collectors;
    
    // 假设 RoleEntity 已定义
    class RoleEntity {
        private Integer id;
        private String name;
    
        public Integer getId() { return id; }
        public void setId(Integer id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }
    
    public class UserEntity {
        private Integer id;
        private String email;
        private Date lastAccessDate;
        private List<RoleEntity> roles; // 用户拥有的角色列表
    
        // 构造函数、其他属性的getter/setter省略
    
        public Integer getId() { return id; }
        public void setId(Integer 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<RoleEntity> getRoles() { return roles; }
        public void setRoles(List<RoleEntity> roles) { this.roles = roles; }
    
        /**
         * 获取用户所有角色的ID列表,并转换为String类型。
         * 如果角色列表为空或为null,则返回一个空列表。
         * @return 包含角色ID(String类型)的列表。
         */
        public List<String> getRoleIds() {
            if (this.roles == null || this.roles.isEmpty()) {
                return Collections.emptyList(); // 避免NullPointerException,返回空列表
            }
            return this.roles.stream()
                    .map(RoleEntity::getId)
                    .map(String::valueOf)
                    .collect(Collectors.toList());
        }
    }
  2. 重构业务方法

    现在,原始的map和updateUser方法可以调用UserEntity中新添加的getRoleIds()方法,从而极大地简化代码。

    重构后的 map 方法:

    import java.util.List;
    import java.util.Date;
    import java.util.stream.Collectors;
    import java.util.Optional;
    
    public class UserService { // 示例服务类
    
        private static final String EMAIL_TYPE = "PRIMARY"; // 示例常量
    
        // 假设 UserDTO 已定义
        public static class UserDTO {
            private String id;
            private Date lastAccessDate;
            private List<String> roles;
            private List<Email> emails;
    
            public String getId() { return id; }
            public void setId(String id) { this.id = id; }
            public Date getLastAccessDate() { return lastAccessDate; }
            public void setLastAccessDate(Date lastAccessDate) { this.lastAccessDate = lastAccessDate; }
            public List<String> getRoles() { return roles; }
            public void setRoles(List<String> roles) { this.roles = roles; }
            public List<Email> getEmails() { return emails; }
            public void setEmails(List<Email> emails) { this.emails = emails; }
    
            public static class Email {
                String address;
                String type;
                public Email(String address, String type) {
                    this.address = address;
                    this.type = type;
                }
            }
        }
    
        protected UserDTO map(UserEntity entity) {
            var result = new UserDTO();
            result.setId(entity.getId().toString());
            result.setLastAccessDate(entity.getLastAccessDate());
            result.setRoles(entity.getRoleIds()); // 调用 UserEntity 的新方法
            if (entity.getEmail() != null) {
                var email = new UserDTO.Email(entity.getEmail(), EMAIL_TYPE);
                result.setEmails(List.of(email));
            }
            return result;
        }
    
        // ... 其他方法 ...
    }

    重构后的 updateUser 方法:

    import java.util.List;
    import java.util.Date;
    import java.util.stream.Collectors;
    import java.util.Optional;
    import org.springframework.data.jpa.repository.JpaRepository; // 假设使用 Spring Data JPA
    
    // 假设 UserResource 已定义
    public static class UserResource {
        private String userName; // 假设此字段用于查找用户ID
        private List<String> roles;
        private Date lastAccessDate;
    
        public String getUserName() { return userName; }
        public void setUserName(String userName) { this.userName = userName; }
        public List<String> getRoles() { return roles; }
        public void setRoles(List<String> roles) { this.roles = roles; }
        public Date getLastAccessDate() { return lastAccessDate; }
        public void setLastAccessDate(Date lastAccessDate) { this.lastAccessDate = lastAccessDate; }
    }
    
    // 假设 UserRepository 接口已定义
    interface UserRepository extends JpaRepository<UserEntity, Integer> {}
    
    public class UserService { // 示例服务类
    
        private UserRepository userRepository; // 假设已通过构造函数或注解注入
    
        // 构造函数用于注入 userRepository
        public UserService(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    
        // 假设 mapToUserEntity 方法已定义
        private UserEntity mapToUserEntity(UserResource updatedUser) {
            UserEntity entity = new UserEntity();
            entity.setId(Integer.valueOf(updatedUser.getUserName())); // 假设 userName 是 ID
            entity.setLastAccessDate(updatedUser.getLastAccessDate());
            // 注意:这里更新实体时,如果 UserResource 也有角色列表,可能需要进一步映射
            // 当前示例主要关注从现有 UserEntity 获取角色ID
            return entity;
        }
    
        public UserResource updateUser(String id, UserResource updatedUser) {
            var optionalUser = userRepository.findById(Integer.valueOf(updatedUser.getUserName()));
            if (optionalUser.isEmpty()) {
                throw new IllegalArgumentException("User not found with ID: " + updatedUser.getUserName());
            }
            // 调用 UserEntity 的新方法
            updatedUser.setRoles(optionalUser.get().getRoleIds());
            updatedUser.setLastAccessDate(optionalUser.get().getLastAccessDate());
            var entity = mapToUserEntity(updatedUser);
            userRepository.save(entity);
            return updatedUser;
        }
    
        // ... 其他方法 ...
    }

优势与最佳实践

  1. 代码复用与可维护性: 最直接的优势是消除了重复代码。任何对角色ID提取逻辑的修改都只需在UserEntity.getRoleIds()方法中进行一次,大大降低了维护成本和出错风险。
  2. 提高可读性与意图表达: 业务方法变得更简洁,更清晰地表达了其核心业务逻辑,而不是纠缠于数据转换的细节。例如,entity.getRoleIds()比一长串流式操作更能直观地传达“获取角色ID列表”的意图。
  3. 增强对象内聚性与封装性: 这种做法符合面向对象设计的“高内聚、低耦合”原则。UserEntity现在封装了关于其自身角色数据如何被处理的知识,而不是将这些知识散布在外部服务中。它增强了UserEntity的领域职责。
  4. 命名规范: 选择一个清晰、描述性的方法名至关重要。getRoleIds()明确指出了方法的目的和返回的数据类型。
  5. 空值处理: 在getRoleIds()方法中,我们加入了对roles列表为null或空时的处理(返回Collections.emptyList()),这是一种健壮的编程实践,可以有效避免NullPointerException。

总结

通过将重复的、与特定实体数据紧密相关的逻辑封装到实体类内部,我们不仅能够有效消除代码重复,还能显著提升代码的可读性、可维护性和对象设计的内聚性。这种重构策略是构建健壮、可扩展的Java应用的关键一步,鼓励开发者将领域知识和行为尽可能地集中到其所属的领域对象中。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3271

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

554

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

562

2026.02.12

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7019

2023.08.02

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

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

549

2023.09.22

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

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

1698

2024.03.01

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

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

7215

2025.09.05

java面向对象
java面向对象

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

362

2025.11.27

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

0

2026.11.03

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn