@Entity
@Getter
@Table(name = "user")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String phoneNumber;
@Column(nullable = false, unique = true)
private String nickname;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserRole role;
@Builder
private User(String email, String password, String phoneNumber, String nickname, UserRole role) {
this.email = email;
this.password = password;
this.phoneNumber = phoneNumber;
this.nickname = nickname;
this.role = role;
}
public static User from(SignupRequestDto requestDto, String password) {
return User.builder()
.email(requestDto.getEmail())
.password(password)
.phoneNumber(requestDto.getPhoneNumber())
.nickname(requestDto.getNickname())
.role(UserRole.USER)
.build();
}
}
@NoArgsConstructor(access = AccessLevel.PROTECTED)
- 아무런 매개변수가 없는 생성자를 생성하되, 다른 패키지에 소속된 클래스는 접근을 불허함
- 왜 접근 권한을 Protected?
- Entity의 'Proxy 조회' 때문
- 정확하게는 엔티티의 연관 관계에서 지연 로딩의 경우에는 실제 엔티티가 아닌 프록시 객체를 통해서 조회를 함
- 프록시 객체를 사용하기 위해서 JPA 구현체는, 실제 엔티티의 기본 생성자를 통해 프록시 객체를 생성하는데, 이 때 접근 권한이 'private' 면 프록시 객체를 생성 X
- 이때 즉시로딩으로 구현하게 되면, 접근 권한과 상관없이 프록시 객체가 아닌 실제 엔티티를 생성하므로 문제 X
- 결론 : 접근 권한을 'private'가 아니라 'protected'로 적용함으로써 프록시 객체를 생성하게 해줄수 있기 때문
- Protected 장점?
- 일반적으로 객체를 생성하고, 객체에 값을 채워 넣는 방법은 3가지
- 기본 생성자를 통해 객체를 생성 후 setter를 통해 필드값 주입
- setter를 통해 언제, 어디서든 객체의 값을 변경할 수 있기에 나중에는 어디서 객체의 값을 변경했는지 추적 어려움
- 객체지향적으로도 옳지 못하기에 권장 X
- 매개변수를 가지는 생성자를 통해 객체 생성과 동시에 필드값 초기화
- 정적 팩토리 메서드 또는 빌더 패턴을 통해 객체를 생성과 동시에 필드 값 초기화
- 2, 3번 -> 무분별한 객체 생성을 방지
- 접근 권한을 public이 아닌 Protected로 제한함으로, 접근 범위를 최대한 작게 설정하는 것