상황
강의를 듣다가 문득 생성자를 직접 코드로 작성하는 이유가 궁금했다. 평소에는 @AllArgsConstructor를 써서 편리함을 챙겼었는데, 튜터님께 직접 생성자를 작성하는 방식과의 차이에 대해 질문했다.
@AllArgsConstructor를 사용한 이유
- 편리함
- 직접 코드를 작성하지 않아도 자동으로 생성자가 생성되기 때문에 편리해서 사용했다.
- 코드의 간결성 및 가독성
- 다른 로직에 집중할 수 있고, 생성자가 많아질수록 가독성이 높아지기 때문에 이 점에서 큰 효과를 봤다.
그럼에도 직접 생성자를 작성하는 이유
1. 필수 필드와 중요성 명확하게 표현
- 직접 생성자 코드를 작성하면, 어떤 필드가 필수적인지, 그 필드의 중요성을 명확하게 표현할 수 있다. 예를 들어, Product 엔티티에서 name과 price는 필수적인 값일 수 있는데, description은 선택적일 수 있다. @AllArgsConstructor는 모든 필드를 생성자의 매개변수로 받아서, description 값이 없으면 문제가 생길 수 있다. 이런 방식은 개발자의 의도가 반영되지 않아서 객체의 일관성을 해칠 수 있다.
@AllArgsConstructor
public class Product {
private String name;
private double price;
private String description;
}
2. 객체 불변성 유지의 어려움
- @AllArgsConstructor를 사용하면 객체의 모든 필드를 초기화할 수 있지만, 이 방식이 불변 객체를 만드는 데 적합하지 않다는 점이 있다. 불변 객체는 객체가 생성된 후 상태가 변경되지 않아야 하는데, @AllArgsConstructor는 생성 후 값을 변경할 수 있는 setter나 다른 메서드와 함께 사용될 수 있다. 불변 객체를 원한다면 생성자에서 모든 필드를 final로 선언하고, setter 메서드를 제공하지 않아야 하는데, @AllArgsConstructor를 쓰면 불변성을 유지하기 어려워진다.
@AllArgsConstructor
public class User {
private final String username;
private final String password;
private String role; // 이 필드는 변경 가능
}
3. 회원가입에 사용되는 엔티티의 경우 불변 객체가 필요
- 예를 들어, 회원가입에 사용되는 UserProfile 엔티티는 불변 객체가 필요하다. 이 객체는 한 번 설정된 후 값이 변경되지 않아야 하므로, @AllArgsConstructor 대신 직접 생성자를 작성하는 게 안정성 측면에서 더 강력할 수 있다.
public final class UserProfile {
private final String email; // 변경되지 않는 값
private final String name; // 변경되지 않는 값
private final LocalDate registrationDate; // 변경되지 않는 값
public UserProfile(String email, String name, LocalDate registrationDate) {
this.email = email;
this.name = name;
this.registrationDate = registrationDate;
}
public String getEmail() {
return email;
}
public String getName() {
return name;
}
public LocalDate getRegistrationDate() {
return registrationDate;
}
}
- 이런 방식은 캡슐화된 객체의 내부 상태를 보호하고, 외부에서 객체를 안전하게 사용하게 만든다. 직접 생성자에서 필수 필드를 명시적으로 정의함으로써 객체의 일관성을 보장하고, 필수 필드를 명확히 구분해서 안정성을 높일 수 있다. 프로젝트가 커지거나 팀이 확장될 때 유지보수에 큰 도움이 된다.
4. 멀티스레딩 환경에서도 안전
- 불변 객체는 멀티스레딩 환경에서도 안전하게 사용할 수 있다. 객체가 변경되지 않기 때문에 여러 스레드가 동시에 접근해도 문제가 발생하지 않는다.
하지만, @AllArgsConstructor를 지양하자는 말은 아니다
@AllArgsConstructor가 적합한 상황도 있다. 해당 엔티티의 필수 필드와 선택적 필드를 구분하기 어렵거나, 빠르게 프로토타입을 만들어야 할 때, 또는 엔티티가 아주 간단한 경우에는 자동 생성자를 사용하는 것이 좋은 대안이 될 수 있다.