무한 생성자 오버로드(overload)
이미 생성자 오버로드가 너무 많았고 나도 거기에 하나를 더 추가해야 하는 상황이 있었다.
생성자를 호출할 때 매개변수에 대한 정보를 알 수 없는 점이 너무 불편했고 코드도 쓸데없이 너무 길어졌다.
// 예시
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
public NutritionFacts() {
this(0)
}
public NutritionFacts(int servingSize) {
this(servingSize, 0)
}
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0)
}
public NutritionFacts(int servingSize, int servings, int calories) {
this(servingSize, servings, calories, 0)
}
public NutritionFacts(int servingSize, int servings, int calories, int fat) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
}
}
// 실제로는 필드가 이거의 세 배는 넘었던 것 같다
이를 점층적 생성자 패턴(Telescoping Constructor Pattern)이라고 하는데 매개변수가 많을 때는 적합하지 않다고 한다.
더 좋은 방법 없나 찾아보다가 그 때 처음 빌더 패턴을 알게 되었다.
Builder Pattern
객체를 직접 만드는 대신 빌더라는 애한테 객체를 만들어달라고 하는 패턴이다.
객체를 직접 만드는 방법
NutritionFacts pepsi = new NutritionFacts(1, 1, 120);
대신
빌더라는 애한테 객체를 만들어 달라고 함
NutritionFacts pepsi = new NutritionFacts.Builder(1, 1)
.calories(120).fat(20).build();
빌더 패턴의 원리
빌더는 생성할 클래스 내부에 static 멤버 클래스로 만듦
각각의 setter(public Builder calories, public Builder fat .. )로 매개변수 설정
build라는 메서드는 만들어 달라고 한 객체를 생성하고 넘겨줌
// 예시 - 이펙티브 자바
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
public static class Builder {
// 필수 매개변수
private final int servingSize;
private final int servings;
// 선택 매개변수 - 기본값으로 초기화한다.
private int calories = 0;
private int fat = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
}
}
빌더 패턴의 장점
- setter명을 통해 매개변수 대한 정보를 알 수 있음
- 직접 생성 시 매개변수 순서 맞춰서 적는 짓 안 해도 됨
- 클래스의 내부 구조 몰라도 객체 생성 가능
- 매개변수 많을 때 너무 편하다
아래는 개발하면서 봤던 Java Slack API의 빌더 패턴
import com.slack.api.methods.MethodsClient;
import com.slack.api.methods.request.chat.ChatPostMessageRequest;
import com.slack.api.methods.response.chat.ChatPostMessageResponse;
public class SlackExample {
// Load an env variable
// If the token is a bot token, it starts with `xoxb-` while if it's a user token, it starts with `xoxp-`
String token = System.getenv("SLACK_TOKEN");
// Initialize an API Methods client with the given token
MethodsClient methods = slack.methods(token);
// Build a request object
ChatPostMessageRequest request = ChatPostMessageRequest.builder()
.channel("#random") // Use a channel ID `C1234567` is preferrable
.text(":wave: Hi from a bot written in Java!")
.build();
// Get a response as a Java object
ChatPostMessageResponse response = methods.chatPostMessage(request);
}
// Java Slack API 코드
빌더 패턴의 단점
- 마찬가지로 매개변수가 너~무 많아지면 코드도 너~무 길어진다
Lombok의 @Builder
롬복의 빌더 어노테이션을 적절히 사용하면 빌더 패턴의 단점을 보완하여 코드를 줄일 수 있다.
'Study > Java' 카테고리의 다른 글
[Java] 제네릭 (0) | 2023.02.01 |
---|---|
JVM 명세 - Run-Time Data Areas (0) | 2022.06.25 |
자바로 간단한 http 웹 서버 구현 (0) | 2022.06.11 |
간단한 자바 TCP 통신 구현 (0) | 2022.06.02 |
[JAVA] 메인메소드 public static void main(String[] args)에 대해 (0) | 2018.09.16 |