💻 하나씩 차곡차곡/Back-end
[Spring] @Builder란? (Feat. 정적 생성 메서드)
뚜루리
2025. 4. 18. 08:54
728x90
320x100
@Builder는 롬복(Lombok)에서 제공하는 애노테이션 중 하나로,
복잡한 객체를 간편하고 가독성 좋게 생성할 수 있도록 도와줌.
@Builder를 사용하는 이유?
[기존방식]
User user = new User("홍길동", "hello@naver.com", 25, "서울");
- 생성자에 들어가는 파라미터 순서가 헷갈릴 수 있음
- 어떤 값이 어떤 필드에 들어가는지 직관적이지 않음=
[@Builder 방식]
User user = User.builder()
.name("홍길동")
.email("hello@naver.com")
.age(25)
.address("서울")
.build();
- 파라미터 순서 상관 없음
- 어떤 필드에 어떤 값이 들어가는지 명확함
- 선택적으로 필드를 설정할 수 있음
가독성 높고 안전함!
사용 방법
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class User {
private String name;
private String email;
private int age;
private String address;
}
- 엔티티 클래스 상단에 @Builder 어노테이션 붙임.
User user = User.builder()
.name("홍길동")
.email("hong@gmail.com")
.age(30)
.build();
🔒 주의할 점
- @Builder는 기본 생성자를 생성해주지 않음 → 필요하면 @NoArgsConstructor 따로 써줘야 함.
- JPA Entity에는 직접 쓰는 것보다 DTO에서 주로 사용하는 걸 추천
@Builder를 Entity에 쓰는 게 위험할 수 있는 이유
항목 | 설명 |
무분별한 생성 우려 | @Builder는 모든 필드를 포함하기 때문에 id, createdAt 같은 관리 대상 필드까지 외부에서 설정할 수 있음 → 실수 가능성 증가 |
JPA 라이프사이클 무시 | JPA는 생성자, 프록시, 영속성 컨텍스트 관리에 민감한데, Builder는 이를 우회하여 객체를 만들 수 있어 예상치 못한 문제가 생길 수 있음 |
불변성 저해 | 엔티티는 보통 생성 이후 일부 필드만 변경(Setter)하는데, Builder는 초기화 목적 외에도 객체를 새로 만들 가능성을 줘서 유지보수가 어려워질 수 있음 |
📌 그렇다면 엔티티에는 @Builder 대신에 어떤걸 사용하는 게 좋을까?
[정적 생성 메서드]
- 정적 생성 메서드는 new 대신 명시적인 이름의 메서드로 객체 생성하고, 생성자의 의도를 명확히 표현할 수 있어 엔티티 클래스에 더 적합함.
public static User create(String email, String encodedPassword, String nickname) {
User user = new User();
user.email = email;
user.password = encodedPassword;
user.nickname = nickname;
user.role = Role.USER;
user.status = UserStatus.ACTIVE;
return user;
}
🔔 정리하자면....
- Entity에는 @Builder를 직접 사용하지 않는 게 좋다: JPA가 사용하는 생성자와 충돌하거나, 필드 초기화 누락 위험 있음.
- Entity에는 정적 팩토리 메서드 사용 권장: 불변성 보장 + 생성 책임 명확.
- DTO에는 @Builder 사용 많이 함: API 응답, 테스트용 객체 만들 때 유용
📌 정적 생성 메서드 + @Builder 조합도 있음!
package ddururi.bookbookclub.domain.user.dto;
import ddururi.bookbookclub.domain.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
@AllArgsConstructor
public class UserResponse {
private Long id;
private String email;
private String nickname;
private String role;
public static UserResponse from(User user) {
return UserResponse.builder()
.id(user.getId())
.email(user.getEmail())
.nickname(user.getNickname())
.role(user.getRole().name())
.build();
}
}
- 정적 생성 메서드 패턴: from(User user)
- 객체 생성 방식을 한눈에 의미 전달.
- User → UserResponse로 변환하는 명확한 목적을 가짐.
- @Builder 사용: UserResponse.builder()...build();
- 가독성 좋고, 필드 많을 때 유지보수 편리.
- 필드 순서와 상관없이 필요한 값만 골라서 세팅 가능.
💡 의도를 명확하게 표현 | from()이란 이름만 봐도 'User 객체로부터 UserResponse를 만든다'는 걸 알 수 있음. |
🔧 변환 책임을 캡슐화 | DTO 변환 로직이 깔끔하게 UserResponse 안에 들어있음. |
🧱 Builder로 가독성과 유연성 확보 | 필드 많아도 가독성이 유지됨. 파라미터 순서 실수 방지. |
♻️ 테스트와 유지보수 쉬움 | 나중에 필드가 추가되어도 한 줄만 더 쓰면 됨. 생성자 바꾸는 것보다 부담 적음. |
🔍 명시적인 팩토리 메서드 활용 | of, from, ofDto, fromEntity 등 이름만으로 의도 파악 쉬움. |
즉, 정적 생성 메서드 + @Builder 조합 =
"객체 생성의 책임은 명확히 하면서도, 가독성과 유지보수를 챙기자"는 실용적인 접근에서 비롯됨.!
728x90
320x100