PHpullh
학습 라이브러리/Java/Builder 패턴 & 불변 객체

JAVA · 디자인패턴

Builder 패턴 & 불변 객체

Effective Java가 권장하는 Builder 패턴으로 복잡한 객체를 안전하게 생성합니다.

디자인패턴중급Builder patternimmutablestatic nested classEffective JavaLombok

핵심 설명

Effective Java가 권장하는 Builder 패턴으로 복잡한 객체를 안전하게 생성합니다.

Java code

import java.util.*;

// 불변 객체 + Builder 패턴
public final class HttpRequest {
    private final String url;
    private final String method;
    private final Map<String, String> headers;
    private final String body;
    private final int timeoutMs;

    private HttpRequest(Builder builder) {
        this.url       = Objects.requireNonNull(builder.url, "url 필수");
        this.method    = builder.method;
        this.headers   = Collections.unmodifiableMap(builder.headers);
        this.body      = builder.body;
        this.timeoutMs = builder.timeoutMs;
    }

    // Getter만 (Setter 없음 — 불변)
    public String url()     { return url; }
    public String method()  { return method; }
    public int timeoutMs()  { return timeoutMs; }

    // static nested Builder
    public static class Builder {
        // 필수
        private final String url;
        // 선택 (기본값 있음)
        private String method  = "GET";
        private Map<String, String> headers = new HashMap<>();
        private String body    = null;
        private int timeoutMs  = 30_000;

        public Builder(String url) { this.url = url; }

        public Builder method(String method)  { this.method = method; return this; }
        public Builder header(String k, String v) { headers.put(k,v); return this; }
        public Builder body(String body)       { this.body = body; return this; }
        public Builder timeout(int ms)         { this.timeoutMs = ms; return this; }

        public HttpRequest build() { return new HttpRequest(this); }
    }

    @Override public String toString() {
        return "HttpRequest{url='%s', method='%s', timeout=%d}"
            .formatted(url, method, timeoutMs);
    }
}

class Main {
    public static void main(String[] args) {
        var req = new HttpRequest.Builder("https://api.example.com/users")
            .method("POST")
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer token123")
            .body("{"name": "Alice"}")
            .timeout(5_000)
            .build();

        System.out.println(req);

        // Lombok @Builder 사용 시 동일 효과:
        // @Builder @Value public class HttpRequest { ... }
    }
}

학습 팁

실무에서는 Lombok의 @Builder를 사용해 보일러플레이트를 제거하는 경우가 많습니다. 직접 구현 시 Effective Java 2장의 패턴을 참고하세요.

주의할 점

Builder에서 build() 이후에 Builder 필드를 수정하면 이미 생성된 객체에 영향이 없습니다. 불변 객체 보장을 위해 Collections.unmodifiableMap()으로 방어적 복사를 하세요.

자주 묻는 질문

Builder 패턴 & 불변 객체란 무엇인가요?

Effective Java가 권장하는 Builder 패턴으로 복잡한 객체를 안전하게 생성합니다.

Builder 패턴 & 불변 객체 학습 시 주의할 점은 무엇인가요?

Builder에서 build() 이후에 Builder 필드를 수정하면 이미 생성된 객체에 영향이 없습니다. 불변 객체 보장을 위해 Collections.unmodifiableMap() 으로 방어적 복사를 하세요.