
在软件开发中,代码重复是一个常见的问题,它不仅增加了维护成本,还容易引入潜在的bug。当一个类中的多个方法执行相似的数据转换或集合处理逻辑时,这通常是进行重构的信号。本教程将通过一个具体的案例,演示如何利用方法提取(Method Extraction)这一重构技术,有效地解决类内代码重复问题。
考虑以下两个Java方法,它们分别负责映射用户实体到DTO和更新用户资源:
原始方法一:map 方法
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);
if (entity.getEmail() != null) {
var email = new UserDTO.Email(entity.getEmail(), EMAIL_TYPE);
result.setEmails(List.of(email));
}
return result;
}原始方法二:updateUser 方法
立即学习“Java免费学习笔记(深入)”;
public 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;
}在这两个方法中,以下代码片段是完全重复的:
.getRoles().stream() .map(RoleEntity::getId) .map(String::valueOf) .collect(Collectors.toList());
这段代码的作用是从 UserEntity 中获取角色列表(List<RoleEntity>),然后将其转换为一个包含角色ID字符串的列表(List<String>)。
解决这种重复代码的最佳实践是将该逻辑封装到一个独立的方法中。关键在于选择合适的方法归属。考虑到这段逻辑是关于 UserEntity 内部角色数据的转换,将其直接添加到 UserEntity 类中是更符合面向对象设计原则的做法。这不仅提高了 UserEntity 的封装性,也使得 UserEntity 自身能够更好地管理和提供其内部数据的不同表示形式。
我们将提取的逻辑封装为 getRoleIds() 方法,并将其添加到 UserEntity 类中。
// UserEntity.java
public class UserEntity {
private Integer id;
private String email;
private Date lastAccessDate;
private List<RoleEntity> roles; // 假设RoleEntity包含getId()方法
// ... 其他属性、构造函数、getter/setter ...
/**
* 获取用户所有角色的ID列表。
* 将List<RoleEntity>转换为List<String> (角色ID)。
* @return 包含角色ID字符串的列表。
*/
public List<String> getRoleIds() {
if (this.roles == null) {
return Collections.emptyList(); // 或根据业务需求返回null
}
return this.roles.stream()
.map(RoleEntity::getId)
.map(String::valueOf)
.collect(Collectors.toList());
}
}
// RoleEntity.java (示例)
public class RoleEntity {
private Integer id;
private String name;
// ... 其他属性、构造函数、getter/setter ...
public Integer getId() {
return id;
}
// ...
}现在,原始方法中的重复代码可以被简洁地替换为对 entity.getRoleIds() 的调用。
优化后的 map 方法
protected UserDTO map(UserEntity entity) {
var result = new UserDTO();
var userRoles = entity.getRoleIds(); // 直接调用UserEntity中的新方法
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()));
// 确保optionalUser不为空,实际生产中应进行null检查或使用orElseThrow
if (optionalUser.isPresent()) {
updatedUser.setRoles(optionalUser.get().getRoleIds()); // 直接调用UserEntity中的新方法
updatedUser.setLastAccessDate(optionalUser.get().getLastAccessDate());
} else {
// 处理用户不存在的情况,例如抛出异常
throw new UserNotFoundException("User with username " + updatedUser.getUserName() + " not found.");
}
var entity = mapToUserEntity(updatedUser);
userRepository.save(entity);
return updatedUser;
}通过方法提取和恰当的封装,我们成功地消除了类内的重复代码,提高了系统的可维护性和可读性。这个案例强调了在重构过程中,不仅要识别重复代码,更要思考将这些重复逻辑封装到何处才能最大化地提升代码质量和符合面向对象设计原则。将与特定实体数据紧密相关的逻辑放置在该实体类内部,是实现高内聚、低耦合的有效手段。
以上就是Java代码重构:通过方法提取优化类内重复逻辑的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号