// UserUtil
public String saveProfileImage(MultipartFile profileImage, User user) {
// 기존 프로필 이미지가 있으면 삭제
if(!Objects.isNull(user.getProfileImagePath())) {
deleteImage(user.getProfileImagePath());
}
String basePath = "myVideos/" + user.getId() + "/images/profile";
String fileName = UUID.randomUUID() + "_" + profileImage.getOriginalFilename();
Path filePath = Paths.get(basePath, fileName);
try {
Files.createDirectories(filePath.getParent());
Files.write(filePath, profileImage.getBytes());
} catch (IOException e) {
throw new RuntimeException("프로필 사진 변경에 실패했습니다.", e);
} return filePath.toString();
}
public String saveBackgroundImage(MultipartFile backgroundImage, User user) {
// 기존 배경 이미지가 있으면 삭제
if(!Objects.isNull(user.getBackgroundImagePath())) {
deleteImage(user.getBackgroundImagePath());
}
String basePath = "myVideos/" + user.getId() + "/images/background";
String fileName = UUID.randomUUID() + "_" + backgroundImage.getOriginalFilename();
Path filePath = Paths.get(basePath, fileName);
try {
Files.createDirectories(filePath.getParent());
Files.write(filePath, backgroundImage.getBytes());
} catch (IOException e) {
throw new RuntimeException("배경 사진 변경에 실패했습니다.", e);
} return filePath.toString();
}
사진을 저장하는 로직은 똑같지만 사진 종류가 다르다는 이유만으로 저장하는 메서드 2개를 정의해버렸다.
사진 종류에 따라서 위치만 다르게 저장하면 된다. 하지만 해당 문제해결 방안이 생각이 안 나서 중복되는 메서드가 하나 더 생겼다. 한층 더 복잡해진 클래스는 보너스다.
리팩토링 기획을 하던 중에 사진 종류를 상수로 만들어서 저장 위치를 동적으로 가져오자는 아이디어가 떠올랐다. 아래는 해당 아이디어 적용 후 결과이다.
// UserUtil
public String saveImage(MultipartFile profileImage, User user, UserImageType userImageType) {
if (!Objects.isNull(userImageType.getImagePathOf(user))) {
deleteImage(userImageType.getImagePathOf(user));
}
String basePath = "myVideos/" + user.getId() + "/images/" + userImageType.getFolderName();
String fileName = UUID.randomUUID() + "_" + profileImage.getOriginalFilename();
Path filePath = Paths.get(basePath, fileName);
try {
Files.createDirectories(filePath.getParent());
Files.write(filePath, profileImage.getBytes());
} catch (IOException e) {
throw new RuntimeException("프로필 사진 변경에 실패했습니다.", e);
}
return filePath.toString();
}
메서드가 받는 파라미터가 하나 더 추가되었다. UserImageType 파라미터를 추가하여 저장할 이미지의 종류를 동적으로 지정할 수 있도록 하였다.
// UserImageType
public enum UserImageType {
PROFILE("profile"){
@Override
public String getImagePathOf(User user) {
return user.getProfileImagePath();
}
},
BACKGROUND("background"){
@Override
public String getImagePathOf(User user) {
return user.getBackgroundImagePath();
}
};
private final String folderName;
public abstract String getImagePathOf(User user);
UserImageType(String folderName) {
this.folderName = folderName;
}
public String getFolderName() {
return folderName;
}
}
이미지타입 상수는 위와 같다. getImagePathOf()
추상 메서드를 필드에서 필요한 대로 정의하였다.
하지만 여기서 더 개선할 수 있다면? 가능하다. 람다식을 사용하면 한 번 더 개선 할 수 있다.
@RequiredArgsConstructor
public enum UserImageType {
PROFILE("profile.jpg", User::getProfileImagePath),
BACKGROUND("background.jpg", User::getBackgroundImagePath);
@Getter
private final String fileName;
private final Function<User, String> userImagePathResolver;
public String getImagePathOf(User user) {
return userImagePathResolver.apply(user);
}
}
롬복과 람다식을 사용하여 코드를 더 간결하게 개선하였다.