
在软件开发中,代码复用是提高效率和维护性的关键。然而,在实际项目中,我们经常会遇到不同方法中存在相似或完全相同的代码片段。这种代码冗余不仅增加了维护成本,也使得代码难以阅读和理解。
以下面的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的提取或转换方式时,我们将不得不在多个地方进行修改,这极易引入错误。
解决代码冗余最有效的方法是将其抽象为一个独立的、职责单一的方法。尽管有时开发者可能希望避免创建“额外”的方法,但从长远来看,这种封装带来的好处远大于其“额外”的成本。
核心思想: 将重复的逻辑提取出来,封装成一个新的方法。这个新方法应该具有清晰的职责,并且可以被多个调用方复用。
最佳实践:将方法放置在相关实体中 对于上述场景,重复的逻辑是关于从UserEntity中获取其关联的RoleEntity的ID列表。这种操作本质上是UserEntity自身数据的一种派生表示。因此,将这个新方法添加到UserEntity类中,使其成为UserEntity的一个行为,是符合面向对象设计原则(如“告诉,不要询问”)的最佳实践。
在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;
}
}现在,我们可以修改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;
}通过上述重构,我们获得了以下显著的益处:
注意事项:
在软件开发中,面对代码冗余时,积极进行重构是提升代码质量的关键。将重复的逻辑封装到职责单一的辅助方法中,并将其放置在最合适的类中(通常是数据实体类),能够显著提高代码的可读性、可维护性和健壮性。这种看似简单的“额外”方法,实则是遵循面向对象设计原则、构建高质量软件的基石。
以上就是如何在同一类中优化方法间重复逻辑的调用的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号