빌더 패턴은 복잡한 객체들을 단계별로 생성할 수 있도록 하는 생성 디자인 패턴입니다.
만들어봅니다!
Entity 역할을 하는 Person의 DTO를 Builder로 변환해 봅시다!
@Getter
@AllArgsConstructor
public class Person {
private String name;
private LocalDate birthday;
private Address address;
}
Person을 Famil, Friend, Coworker 등으로 확장하면서 구현해보기 위해 Interface를 만들어봅니다.
public interface PersonDTO {
String getName();
LocalDate getBirthday();
Address getAddress();
}
PersonDTO를 구현한 FriendDTO는 아래와 같습니다.
nickname 필드를 추가했습니다.
@Getter
@AllArgsConstructor
@ToString
public class FriendDTO implements PersonDTO {
private String name;
private String nickname;
private LocalDate birthday;
private Address address;
}
빌더 패턴을 사용하면, 매개변수가 많을 경우, 매개변수의 조합이 많을 경우 간편하게 불변 객체를 만들 수 있습니다.
빌더 클래스도 DTO 클래스와 동일하게 interface를 만들고 구현 객체를 만듭니다.
🙅♂️ 아래 코드는 나중에 수정이 될 것입니다^^,,,
public interface PersonDTOBuilder {
PersonDTOBuilder name(String name);
PersonDTOBuilder birthday(LocalDate birthday);
PersonDTOBuilder address(Address address);
PersonDTO build();
}
public class FriendDTOBuilder implements PersonDTOBuilder {
private String name;
private String nickname;
private LocalDate birthday;
private Address address;
@Override
public FriendDTOBuilder name(String name) {
this.name = name;
return this;
}
public FriendDTOBuilder nickname(String nickname) {
this.nickname = nickname;
return this;
}
@Override
public FriendDTOBuilder birthday(LocalDate birthday) {
this.birthday = birthday;
return this;
}
@Override
public FriendDTOBuilder address(Address address) {
this.address = address;
return this;
}
@Override
public PersonDTO build() {
return new FriendDTO(name, nickname, birthday, address);
}
}
이렇게 작성하면 Builder 패턴으로 객체를 만들 수 있으나..
모든 새로운 빌더마다 반환 타입을 다시 지정해줘야 하는 번거로움이 생기고, 반환 타입을 실수할 가능성이 높아집니다..
제네릭을 사용해서 조금 더 안전한 코드를 만들어봅시다.
public interface PersonDTOBuilder<T extends PersonDTOBuilder<T>> {
T name(String name);
T birthday(LocalDate birthday);
T address(Address address);
PersonDTO build();
PersonDTO getPersonDTO();
}
여기서 그치지 않고, Builder를 품은 DTO도 만들 수 있습니다,,🤗
@Getter
@Setter
@ToString
@AllArgsConstructor
public class CafeDTO {
private String name;
private String address;
private String signature;
private String rating;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private String address;
private String signature;
private String rating;
private CafeDTO cafeDTO;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder address(Address address) {
this.address = "(" + address.getZipCode() + ") " + address.getCity() + " " + address.getState();
return this;
}
public Builder signature(String signature) {
this.signature = signature;
return this;
}
public Builder rating(int rating) {
this.rating = "★".repeat(rating);
return this;
}
public CafeDTO build() {
this.cafeDTO = new CafeDTO(name, address, signature, rating);
return this.cafeDTO;
}
public CafeDTO getCafeDTO() {
return this.cafeDTO;
}
}
}
이제야 자주보던 @Builder를 선언했을 때와 같은 모양으로 쓸 수 있습니다,,
CafeDTO cafe = CafeDTO.builder()
.name("starbucks")
.address(address)
.signature("americano")
.rating(5)
.build();
여기에 마지막으로 Entity를 DTO로 바꿔주는 static 메서드도 추가가 가능하죠,,
public static CafeDTO toDTO(Cafe cafe) {
return CafeDTO.builder()
.name(cafe.getName())
.address(cafe.getAddress())
.signature(cafe.getSignature())
.rating(cafe.getRating())
.build();
}
Entity를 DTO로,,
Cafe cafe = new Cafe("two-some", new Address("12345", "seoul", "bangbae"), "milktea", 5);
CafeDTO cafeDTOFromEntity = CafeDTO.toDTO(cafe);
📑
참고 자료
Chat GPT
💠 빌더(Builder) 패턴 - 완벽 마스터하기
Builder Pattern 빌더 패턴(Builder Pattern)은 복잡한 객체의 생성 과정과 표현 방법을 분리하여 다양한 구성의 인스턴스를 만드는 생성 패턴이다. 생성자에 들어갈 매개 변수를 메서드로 하나하나 받아
inpa.tistory.com
https://refactoring.guru/ko/design-patterns/builder
빌더 패턴
/ 디자인 패턴들 / 생성 패턴 빌더 패턴 다음 이름으로도 불립니다: Builder 의도 빌더는 복잡한 객체들을 단계별로 생성할 수 있도록 하는 생성 디자인 패턴입니다. 이 패턴을 사용하면 같은 제작
refactoring.guru