
在复杂的业务系统中,我们经常会遇到需要在不同服务或映射方法中对同一实体对象进行相同的数据处理或转换。例如,在将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免费学习笔记(深入)”;
实现步骤与示例
在 UserEntity 中添加新方法
我们将创建一个名为getRoleIds()的新方法,将其添加到UserEntity类中。该方法将负责执行原先重复的流式操作,并返回一个List<String>。
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());
}
}重构业务方法
现在,原始的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;
}
// ... 其他方法 ...
}通过将重复的、与特定实体数据紧密相关的逻辑封装到实体类内部,我们不仅能够有效消除代码重复,还能显著提升代码的可读性、可维护性和对象设计的内聚性。这种重构策略是构建健壮、可扩展的Java应用的关键一步,鼓励开发者将领域知识和行为尽可能地集中到其所属的领域对象中。
以上就是Java代码重构:通过实体类方法封装重复逻辑提升代码复用性的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号