매개변수가 많은 생성자의 단점을 그대로 가짐 -> 순서가 뒤섞일 수 있고 가독성이 떨어져 오류를 찾기 힘듦
(정보가 주어지지 않은 값은 보통 null로 초기화할 텐데 좋은 습관은 아닐 듯)
기존 시도 2. JavaBeans 패턴
매개변수가 없는 생성자로 객체 생성 > setter를 이용해 값을 채움
public class Article {
// ...
public Article() {}
public void setOid(String oid) {
this.oid = oid;
}
public void setAid(String aid) {
this.aid = aid;
}
// ...
}
public static void main() {
Article article = new Article();
article.setOid("057");
article.setAid("0001645171");
}
- 객체 생성을 위해 여러 번 메서드 호출이 필요하고, 모든 setter 호출 완료 이전까지 일관성이 무너진 상태로 남는다.
- Immutability를 구현할 수 없다.
### Builder 패턴
- 점층적 생성자 패턴의 안정성과 자바빈 패턴의 가독성을 겸비
- 필수 매개변수만으로 생성자를 호출하여 빌더 객체를 얻어 이를 이용해 객체 생성
- setter 역할 메서드로 매개변수 설정 후, build하여 immutable한 객체 생성
```java
public class Article {
// ...
public static class Builder {
private final String oid;
private final String aid;
private String content;
public Builder(String oid, String aid) {
this.oid = oid;
this.aid = aid;
}
public Builder content(String content) {
this.content = content;
return this;
}
public Article build() {
return new Article(oid, aid, content);
}
}
}
@Test
public void articleTest() {
Article article = new Article.Builder("057", "0001645171")
.content("지지를 호소했습니다.")
.build();
System.out.println(article);
}
빌더의 setter 메서드가 빌더 자신을 반환하기 때문에 읽기 쉬운 연쇄적인 호출이 가능하다.
객체 생성을 위한 필수값, 기본값, 인자 유효성 검사 로직을 Builder에 녹일 수 있다.
Builder 패턴의 단점
객체 생성에 앞서 상대적으로 복잡한 Builder를 만들어야 한다.
필요한 인자 수가 많지 않으면 굳이 필요가 없다.
그러나 API는 인자가 많아지는 경향이 있으므로 처음부터 빌더를 이용해도 좋을 것
계층 구조 ❤️ Builder 패턴
빌더 패턴은 계층적으로 설계된 클래스와 함께 쓰기 좋다.
책 예제에서는 class Builder<T extends Builder<T>>를 만들어 이를 상속, 호출하는 방식으로 구현.
Lombok
Lombok의 @Builder를 클래스나 생성자에 붙여 Builder 패턴을 쉽게 구현할 수 있다!
@SuperBuilder를 이용하면 상위 클래스 필드가 포함된 Builder를 생성할 수 있다. (experimental feature)
@Singular를 이용하면 java.util.Collection 타입 필드에 아이템을 하나씩 추가하는 빌더 메서드를 이용할 수 있다!
// 책 예제와 동일한 결과를 반환
@SuperBuilder
public abstract class Pizza {
public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
@Singular
final Set<Topping> toppings;
}
@SuperBuilder
public class Calzone extends Pizza {
private final boolean sauceInside;
}
@SuperBuilder
public class NyPizza extends Pizza {
public enum Size {SMALL, MEDIUM, LARGE}
private final Size size;
}
@Test
public void pizzaTest() {
NyPizza pizza = NyPizza.builder().size(SMALL)
.topping(SAUSAGE).topping(ONION).build();
Calzone calzone = Calzone.builder().topping(HAM)
.sauceInside(true).build();
}
객체 생성에 필요한 매개변수가 많아질 때, 정적 팩토리 & 생성자는 이를 대응하기 어려움 -> Builder를 쓰자
기존 시도 1. 점층적 생성자 패턴
매개변수가 많은 생성자 + 기본값 적용 방식으로 매개변수가 적은 생성자 구현
기존 시도 2. JavaBeans 패턴
매개변수가 없는 생성자로 객체 생성 > setter를 이용해 값을 채움
public static void main() { Article article = new Article(); article.setOid("057"); article.setAid("0001645171"); }
Builder 패턴의 단점
계층 구조 ❤️ Builder 패턴
class Builder<T extends Builder<T>>
를 만들어 이를 상속, 호출하는 방식으로 구현.Lombok
@Builder
를 클래스나 생성자에 붙여 Builder 패턴을 쉽게 구현할 수 있다!@SuperBuilder
를 이용하면 상위 클래스 필드가 포함된 Builder를 생성할 수 있다. (experimental feature)@Singular
를 이용하면java.util.Collection
타입 필드에 아이템을 하나씩 추가하는 빌더 메서드를 이용할 수 있다!참고 : Kotlin, DSL 기반 Builder