Setter의 사용 금지
프로젝트 진행중 엔티티나 DTO에 setter를 사용하게 되는 일이 종종 발생하게 되는데,
이는 일관성 유지에 어려움 등의 여러가지 문제점으로 인해 사용이 금지된다.
① Setter 사용의 의도를 알기 어려움
public ActivityCreateDTO saveActivity(ActivityCreateDTO activityCreateDTO) {
Activity activity = new Activity();
activity.setName(activityCreateDTO.getName());
activity.setDescription(activityCreateDTO.getDescription());
activity.setScore(activityCreateDTO.getScore());
activityRepository.save(activity);
activityRepository.save(activity);
return new ActivityCreateDTO(activity);
}
보통 setter는 위와 같이 엔티티의 값을 변경하고자 할 때 많이 사용되는데 setter로 값을 변경하는 의도가 분명하지가 않다. 어떤 변화를 주기 위해서 값을 변경하는지 명확한 의도를 나타내지 않는다.
public class Activity {
private Integer id;
private String name;
private Integer score;
private String description;
public Activity(String name, Integer score, String description) {
this.name = name;
this.score = score;
this.description = description;
}
// 비지니스 로직
public Activity updateActivity( Activity requestActivity) {
this.name = requestActivity.name;
this.description = requestActivity.description;
this.score = requestActivity.score;
return this;
}
}
public ActivityCreateDTO updateActivity(ActivityCreateDTO activityCreateDTO,
MultipartFile multipartFile) {
Activity existingActivity = activityRepository.findById(activityCreateDTO.getId())
.get();
Activity requestActivity = activityCreateDTO.toActivity();
Activity updatedActivity = existingActivity.updateActivity(requestActivity);
activityRepository.save(existingActivity);
return new ActivityCreateDTO(existingActivity);
}
위와 같이 엔티티에 값을 변경하고자 하는 비지니스로직을 생성 해주고 service계층에서는 updateActivity 로직을 사용하므로서 값을 변경하고자 하는 의도를 지닌 로직명을 명확히 하고 변경 이유를 알려주도록 한다.
② 값의 일관성 유지에 어려움
자바의 빈 규제에 따라서 setter 는 public 으로 모든 곳에서 접근이 가능하기 때문에 의도치 않게 값이 변경되는 경우가 발생할 수 있다.
@Builder의 사용
멤버 변수가 많고, 다양한 생성자를 가져야 하는 경우에는 객체 생성시점에 값을 넣어주어 객체 값의 일관성을 유지하도록 돕는 @Builder를 사용할 수 있다.
public class ActivityCreateDTO {
private Integer id;
private String name;
private Integer score;
private String description;
private String imageUrl;
public ActivityCreateDTO(String name, Integer score, String description) {
this.name = name;
this.score = score;
this.description = description;
}
public ActivityCreateDTO(Integer id, String name, Integer score, String description) {
this.id = id;
this.name = name;
this.score = score;
this.description = description;
}
}
원래의 경우 setter값을 지양하고자 많은 생성자를 지니게 된다.
public class ActivityCreateDTO {
private Integer id;
private String name;
private Integer score;
private String description;
private String imageUrl;
@Builder
public ActivityCreateDTO(Integer id, String name, Integer score, String description) {
this.id = id;
this.name = name;
this.score = score;
this.description = description;
}
}
Activity activity = Activity.Builder()
.name("name")
.score(12)
.description("description")
.build()
위와 같이 @Builder를 사용하게 되면 많은 생성자를 사용할 필요 없이 setter의 사용을 줄일 수 있다.
public class Activity {
protected Activity() {};
}
기본 생성자를 기본적으로 필요로하는 JPA의 경우 protected까지 생성자를 제어하는 것을 지원하므로 new Activity() 의 사용을 막을 수 있어 객체를 더욱 일관성 있게 유지할 수 있다.
@NoArgsContructor(access = AccessLevel.PROTECTED)
public class Activity {
protected Activity() {};
}
롬복을 사용하면 더 편하게 나타낼 수 있다.
(참고한 사이트)
https://bloowhale.tistory.com/97