Builder Pattern
빌더 패턴은 객체를 생성할 때 생성자가 여러 개의 인자를 가질 때 사용할 수 있는 객체 생성 패턴입니다.
빌더 패턴을 사용하면 인자가 많은 생성자를 사용할 때 인자를 쉽게 설정할 수 있습니다.
빌더 패턴을 사용하려면 우선 클래스의 인스턴스를 생성할 수 있는 빌더 클래스를 정의해야 합니다. 빌더 클래스는 생성자의 인자들을 필드로 가지고 있으며, 각각의 필드에 대해 setter 메소드를 정의합니다. 이렇게 정의된 빌더 클래스를 사용해 객체를 생성할 때는 인스턴스를 생성할 때 원하는 필드만 설정해서 생성할 수 있습니다.
예를 들어, 아래와 같은 피자 클래스가 있다고 가정해봅시다.
public class Pizza {
private final int size;
private final boolean cheese;
private final boolean pepperoni;
private final boolean bacon;
private Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) {
this.size = size;
this.cheese = cheese;
this.pepperoni = pepperoni;
this.bacon = bacon;
}
}
이렇게 정의된 클래스의 인스턴스를 생성하기 위해서는 생성자를 사용해야 하는데, 생성자의 인자가 많기 때문에 생성자를 사용할 때 각각의 인자값을 입력하기가 어렵습니다. 이를 해결하기 위해서 빌더 패턴을 사용할 수 있습니다.
빌더 패턴을 적용한 코드는 아래와 같습니다.
public class Pizza {
private final int size;
private final boolean cheese;
private final boolean pepperoni;
private final boolean bacon;
private Pizza(PizzaBuilder builder) {
this.size = builder.size;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.bacon = builder.bacon;
}
public static class PizzaBuilder {
private int size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
public PizzaBuilder size(int size) {
this.size = size;
return this;
}
public PizzaBuilder cheese(boolean cheese) {
this.cheese = cheese;
return this;
}
public PizzaBuilder pepperoni(boolean pepperoni) {
this.pepperoni = pepperoni;
return this;
}
public PizzaBuilder bacon(boolean bacon) {
this.bacon = bacon;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
이제 인스턴스를 생성할 때는 아래와 같이 코드를 작성할 수 있습니다.
Pizza pizza = new Pizza.PizzaBuilder()
.size(12)
.cheese(true)
.pepperoni(true)
.bacon(false)
.build();
이렇게 코드를 작성할 수 있기 때문에 인스턴스를 생성할 때 코드가 간결해집니다.
또한 원하는 필드만 선택해 생성할수 있습니다.
Pizza pizza = new Pizza.PizzaBuilder()
.bacon(true)
.build();
주의사항
빌더 패턴을 사용할 때는 주의해야 할 점도 있습니다.
정적 타입 체크가 일반 클래스와 달리 적용되지 않기 때문에 오타가 있거나 잘못된 값이 설정될 가능성이 있어 일반 클래스와 달리 타입 안정성이 떨어질수 있습니다. 이는 빌더 클래스가 상속 구조를 가지고 있지 않기 때문입니다.
그래서, 빌더 패턴을 사용할 때는 상황에 맞게 적절히 사용해야 합니다. 인자가 많거나, 인자들 중 일부만 설정해야 할 경우에는 빌더 패턴을 사용하는 것이 좋고, 인자가 적고 필수인 경우에는 일반 생성자를 사용하는 것이 좋습니다.
Lombok에서의 @Builder
Lombok에는 여러가지 유용한 어노테이션이 제공되는데, 이 중 하나가 @Builder 어노테이션입니다. @Builder 어노테이션은 빌더 패턴을 적용할 때 사용할 수 있습니다.
@Builder 어노테이션을 사용하면 아래와 같이 코드를 작성할 수 있습니다.
@Builder
public class Pizza {
private int size;
private boolean cheese;
private boolean pepperoni;
private boolean bacon;
}
@Builder 어노테이션을 사용하면 자동으로 빌더 클래스가 생성됩니다. 이렇게 생성된 빌더 클래스를 사용하면 아래와 같이 인스턴스를 생성할 수 있습니다.
Pizza pizza = Pizza.builder()
.size(12)
.cheese(true)
.pepperoni(true)
.bacon(false)
.build();
이때 생성자와 달리 각각의 필드들을 설정할 수 있기 때문에 필수로 설정해야 할 필드들을 설정하지 않은 경우에 예외가 발생할 수 있습니다. 이러한 상황을 방지하기 위해서는 필수로 설정해야 할 필드들에 대해서 @NonNull 어노테이션을 사용할 수 있습니다.
@NonNull 어노테이션을 사용하면 해당필드가 null일 경우에 컴파일 시점에 예외가 발생합니다. 이렇게 하면 필수로 설정해야 할 필드들이 설정되지 않은 상태로 인스턴스가 생성되는 것을 방지할 수 있습니다.
'JAVA' 카테고리의 다른 글
| Smart Store 토이 프로젝트 #4 고객 분류 매개변수 메뉴 (0) | 2022.11.24 |
|---|---|
| Smart Store 토이 프로젝트 #3 고객 분류 매개변수 메뉴 (0) | 2022.11.18 |
| Smart Store 토이 프로젝트 #2 고객 정보 관리 메뉴 (0) | 2022.10.24 |
| Smart Store 토이 프로젝트 #1 구조 (0) | 2022.10.23 |