Builder Pattern
Builder Pattern 은 복잡한 객체 생성 문제를 해결하는 창조적 디자인 패턴으로, Director, Builder, ConcreteBuilder, Product 의 4 가지 핵심 구성요소를 통해 단계별 객체 구성을 지원한다. 생성자 오버로딩 문제를 해결하고 불변 객체 생성을 가능하게 하며, 플루언트 인터페이스를 통한 메서드 체이닝으로 코드 가독성을 크게 향상시킨다. 현대 프레임워크와 라이브러리에서 널리 활용되고 있다.
핵심 개념
Builder Pattern 은 복잡한 객체의 생성 과정을 단계별로 분리하여, 동일한 생성 절차에서 다양한 표현의 객체를 생성할 수 있도록 하는 생성 패턴이다. 객체 생성이 여러 단계로 나뉘거나, 다양한 조합의 옵션이 존재할 때 적합하다.
- 복잡한 객체의 생성과 표현을 분리하는 패턴
- 단계별 객체 생성을 통한 유연성 제공
- 동일한 생성 과정으로 다양한 표현 가능
핵심 정의
- 분리의 원칙: 객체 생성 과정과 객체의 표현을 분리
- 단계적 구성: 복잡한 객체를 단계별로 구성
- 다형성 지원: 동일한 구성 과정으로 다양한 객체 생성
- 캡슐화: 구성 로직을 별도의 빌더 클래스에 캡슐화
의도
복잡한 객체의 생성 과정과 표현 방법을 분리하여, 동일한 생성 절차로 다양한 형태의 객체를 단계별로 생성할 수 있도록 한다.
다른 이름 (Also Known As)
- 생성자 체이닝 패턴 (Constructor Chaining Pattern)
- 점층적 생성자 패턴 (Telescoping Constructor Pattern, 대체/극복 패턴)
동기 (Motivation / Forces)
- 생성자 매개변수가 많거나, 선택적/필수 매개변수 혼합 시 코드 복잡성 증가
- 생성자/자바빈 패턴의 단점 (순서 오류, 불변성 미보장, 일관성 깨짐) 극복
- 복잡한 객체의 단계별 생성 및 다양한 조합 지원 필요.
적용 가능성 (Applicability)
- 매개변수가 많거나 선택적/필수 매개변수 혼합 객체 생성
- 불변 객체 생성, 복잡한 DTO, 설정 객체, 테스트 데이터 생성
- 생성 과정이 단계별로 분리될 필요가 있을 때.
6.19 패턴이 해결하고자 하는 설계 문제
핵심 설계 문제들:
생성자 매개변수 급증 문제 (Telescoping Constructor Problem)
- 여러 개의 선택적 매개변수로 인한 생성자 오버로딩
- 매개변수 순서 혼동 및 가독성 저하
객체 상태 불일치 문제
- 부분적으로 초기화된 객체의 위험성
- 유효하지 않은 상태의 객체 생성 가능성
불변 객체 생성의 어려움
- 복잡한 불변 객체 생성 시 중간 상태 노출
- 스레드 안전성 확보의 복잡성
관련 패턴 (Related Patterns)
- Abstract Factory: 제품군 생성 vs 단일 복잡 객체 생성
- Composite: 복합 객체 구조 생성 시 활용
- Factory Method: 단순 생성 → 복잡 생성으로의 진화
- Prototype: 복제 기반 vs 생성 기반 접근
6.22 유사하거나 관련된 패턴들
패턴명 | 관계 | 차이점 | 결합 사용 |
---|---|---|---|
Factory Method | 대체 관계 | Factory 는 즉시 생성, Builder 는 단계적 생성 | 빌더 생성 시 Factory Method 활용 |
Abstract Factory | 보완 관계 | Abstract Factory 는 관련 객체군 생성 | 복잡한 객체 계층에서 함께 사용 |
Prototype | 대체 관계 | Prototype 은 복제 기반, Builder 는 구성 기반 | 기본 템플릿 복제 후 빌더로 커스터마이징 |
Composite | 결합 관계 | Composite 트리 구조를 Builder 로 생성 | 복잡한 트리 구조 객체 생성 시 |
Strategy | 결합 관계 | 빌드 전략을 Strategy 패턴으로 구현 | 다양한 빌드 알고리즘 선택 시 |
실무 구현 연관성
객체 생성 최적화 측면:
- 불변 객체 (Immutable Object) 패턴과의 연계
- 팩토리 패턴과의 차별화된 역할 분담
- 유효성 검증 로직의 중앙화
코드 품질 향상 측면:
- 플루언트 인터페이스 (Fluent Interface) 구현
- 메서드 체이닝 (Method Chaining) 을 통한 가독성 향상
- 선택적 매개변수 처리의 체계화
아키텍처 설계 측면:
- Domain-Driven Design (DDD) 에서의 Aggregate 생성
- 마이크로서비스 아키텍처에서의 DTO 생성
- 설정 객체 (Configuration Object) 패턴과의 결합
배경
Builder Pattern 은 다음과 같은 문제를 해결하기 위해 등장했다:
- 점층적 생성자 패턴 (Telescoping Constructor Pattern) 의 한계
- 매개변수가 많아질수록 가독성 저하
- 매개변수 순서 기억의 어려움
- 코드 유지보수성 문제
- 자바빈 패턴 (JavaBeans Pattern) 의 문제점
- 객체 일관성 (Consistency) 깨짐
- 불변 객체 생성 불가
- 스레드 안전성 문제
목적 및 필요성
주요 목적:
- 구성과 표현의 분리: 객체 생성 로직을 별도로 관리
- 단계적 구성: 복잡한 객체를 단계별로 안전하게 생성
- 코드 가독성 향상: 직관적인 객체 생성 API 제공
- 유연성 확보: 다양한 구성 옵션 지원
필요성:
- 복잡한 도메인 객체 생성 시 필수
- API 설계에서 사용자 친화적 인터페이스 제공
- 테스트 코드에서 객체 생성의 명확성 확보
- 설정 관리 시스템에서의 체계적 접근
주요 기능 및 역할
핵심 기능:
단계별 객체 구성
- 필수 속성과 선택적 속성의 구분
- 속성 설정 순서의 유연성 제공
- 중간 상태 검증 가능
다양한 표현 생성
- 동일한 구성 과정으로 다른 형태의 객체 생성
- 구성 옵션에 따른 객체 변형
- 조건부 속성 설정
유효성 검증
- 빌드 단계에서의 일괄 검증
- 비즈니스 규칙 적용
- 에러 처리의 중앙화
특징
구분 | 특징 | 설명 |
---|---|---|
구조적 | 분리된 구성 | 객체 생성 로직이 별도 클래스로 분리 |
행위적 | 단계적 구성 | 객체를 단계별로 구성하는 방식 |
인터페이스 | 플루언트 API | 메서드 체이닝을 통한 직관적 사용 |
유연성 | 다형성 지원 | 다양한 빌더 구현체 지원 |
안전성 | 불변성 보장 | 완성된 객체의 불변성 확보 |
핵심 원칙
Single Responsibility Principle (SRP)
- 빌더는 객체 생성에만 집중
- 각 빌더는 특정 타입의 객체 생성 담당
Open/Closed Principle (OCP)
- 새로운 빌더 추가 시 기존 코드 수정 불필요
- 확장에는 열려있고 변경에는 닫혀있음
Dependency Inversion Principle (DIP)
- 클라이언트는 구체적 빌더가 아닌 인터페이스에 의존
- 구현체 변경 시 클라이언트 코드 영향 최소화
주요 원리
- 위임 원리: Director 가 Builder 에게 구성 작업 위임
- 추상화 원리: Builder 인터페이스를 통한 구현체 추상화
- 조합 원리: 여러 구성 요소를 조합하여 최종 객체 생성
- 캡슐화 원리: 구성 로직을 빌더 내부에 캡슐화
설계 구조와 관계
Builder Pattern 의 설계 구조는 다음과 같은 관계를 형성한다:
graph LR subgraph "Client Layer" CL[Client Code] end subgraph "Builder Layer" DIR[Director] BI[Builder Interface] CB1[ConcreteBuilder A] CB2[ConcreteBuilder B] end subgraph "Product Layer" PA[Product A] PB[Product B] end CL --> DIR CL --> BI DIR --> BI BI --> CB1 BI --> CB2 CB1 --> PA CB2 --> PB style CL fill:#e1f5fe style DIR fill:#f3e5f5 style BI fill:#e8f5e8 style CB1 fill:#fff3e0 style CB2 fill:#fff3e0 style PA fill:#fce4ec style PB fill:#fce4ec
관계 설명:
- 의존 관계: Client 는 Builder Interface 에만 의존
- 구현 관계: ConcreteBuilder 가 Builder Interface 구현
- 생성 관계: ConcreteBuilder 가 구체적인 Product 생성
- 제어 관계: Director 가 빌드 프로세스 제어 (선택적)
작동 원리 및 방식
sequenceDiagram participant Client participant Director participant Builder participant Product Client->>Director: construct() Director->>Builder: buildPartA() Builder->>Builder: create PartA Director->>Builder: buildPartB() Builder->>Builder: create PartB Director->>Builder: buildPartC() Builder->>Builder: create PartC Director->>Builder: getResult() Builder->>Product: new Product(parts) Builder-->>Director: return Product Director-->>Client: return Product
작동 방식 설명:
- 초기화 단계: 클라이언트가 빌더 인스턴스 생성
- 구성 단계: 단계별로 객체 속성 설정
- 검증 단계: 빌드 전 유효성 검증 수행
- 생성 단계: 최종 객체 생성 및 반환
- 정리 단계: 빌더 상태 초기화 (재사용 시)
패턴 적용의 결과와 트레이드오프
긍정적 결과:
- 코드 가독성 및 유지보수성 향상
- 객체 생성 과정의 표준화
- 다양한 객체 표현 생성 가능
- 불변 객체 생성 지원
트레이드오프:
- 코드 복잡성 증가 vs 유연성 확보
- 성능 오버헤드 vs 안전성 보장
- 개발 시간 증가 vs 장기적 유지보수 비용 절감
전체 구조
classDiagram class Director { -builder: Builder +construct() +setBuilder(builder: Builder) } class Builder { <<interface>> +buildPartA() +buildPartB() +buildPartC() +getResult() Product } class ConcreteBuilderA { -product: ProductA +buildPartA() +buildPartB() +buildPartC() +getResult() ProductA } class ConcreteBuilderB { -product: ProductB +buildPartA() +buildPartB() +buildPartC() +getResult() ProductB } class Product { <<abstract>> } class ProductA { -partA: String -partB: String -partC: String } class ProductB { -partA: Integer -partB: Boolean -partC: Object } Director --> Builder Builder <|-- ConcreteBuilderA Builder <|-- ConcreteBuilderB ConcreteBuilderA --> ProductA ConcreteBuilderB --> ProductB Product <|-- ProductA Product <|-- ProductB
필수 구성요소
구성요소 | 기능 | 역할 | 특징/활용 시기 |
---|---|---|---|
Builder (Interface) | 빌드 메서드 정의 | 공통된 빌드 인터페이스 제공 | 필수 구성요소. 다양한 ConcreteBuilder 에 대한 계약 역할 수행 |
ConcreteBuilder | 구체적 빌드 구현 | 실제 객체 생성 로직 수행 | 필수 구성요소. 제품 속성에 따라 다양한 구현 가능 |
Product | 최종 객체 생성 | 빌더가 조립하는 결과물 객체 | 필수 구성요소. 복잡한 내부 구조를 가질 수 있음 |
Director | 빌드 순서 제어 | 빌드 프로세스 관리 및 표준화 | 선택 구성요소. 복잡한 빌드 순서를 클라이언트에서 분리할 필요가 있을 때 사용 |
Abstract Product | 제품 타입 추상화 | 다양한 제품 유형에 대한 공통 인터페이스 정의 | 선택 구성요소. 여러 제품군 생성 시 활용 |
Builder Factory | 빌더 인스턴스 생성/선택 관리 | 상황에 맞는 빌더 생성 및 선택 제어 | 선택 구성요소. 설정 기반 동적 선택, 전략 패턴과 연계 가능 |
구현 기법
구현 방식 | 설명 | 장점 | 대표 사례 / 사용 언어 |
---|---|---|---|
Classic GoF Builder | Director 가 빌드 순서를 제어하고, Builder 인터페이스로 구현 분리 | 빌드 과정의 명확한 단계화, 복잡한 객체 조립에 적합 | Java, Python (TextConverter 등) |
Fluent Builder | 메서드 체이닝 방식으로 직관적 객체 생성 (withX().withY().build() ) | 코드 가독성, 선언적 스타일, 순서 유연성 | JavaScript, Java (HttpRequest 등) |
Effective Java 스타일 | 내부 정적 클래스 방식, 필수/선택 속성 구분 명확 | 불변 객체, 명확한 생성자 구조, 코드 응집도 높음 | Java (Pizza 예제 등) |
Internal Builder | Product 클래스 내부에 Builder 중첩 정의 | 외부 노출 없이 캡슐화, 작은 객체군에 적합 | Java (Effective Java), Kotlin |
External Builder | Product 외부에 Builder 클래스를 분리하여 설계 | 여러 Product 간 공유 및 확장 용이 | Java, C++, JS |
Functional Builder / DSL | 함수형 언어에서 빌더를 함수 조합 또는 DSL 형태로 구현 | 불변성 중심 설계, 간결하고 명시적인 객체 구성 | Python, Kotlin DSL, JavaScript |
Generic Builder | 제네릭을 활용해 타입 안정성 보장, 유연한 객체 구성 지원 | 타입 안전성, 재사용성, 공통 빌더 구현에 적합 | Java, TypeScript |
Step Builder | 단계별 타입을 반환하여 필수 설정 순서를 강제하는 구현 | 필수값 누락 방지, 유효성 보장 | Java, Kotlin |
Lombok @Builder | 어노테이션 기반 자동 생성 | 개발 편의성, 코드 자동화, 빠른 적용 | Java + Lombok |
Validation 포함 Builder | build() 시점에 유효성 검사 수행 (필수 필드 누락, 형식 검증 등) | 안정성 확보, 런타임 오류 방지 | 모든 언어 가능 (Fluent + Validation) |
Immutable Builder | build() 이후 객체 변경 불가. Setter 미제공 | 스레드 안전성, 신뢰 가능한 상태 보장 | Java, Kotlin, Scala |
Builder Factory | 다양한 빌더 생성/선택을 팩토리에서 처리 | 설정 기반 선택, DI/Strategy 와 연계 가능 | Java, Spring, 설정 기반 시스템 |
Classic GoF Builder (Director 포함)
설명: 전통적 형태의 Builder. Builder 인터페이스, ConcreteBuilder, Product, Director 구성.
예시 (Python):
|
|
Fluent Builder (Method Chaining)
설명: withX().withY().build()
형태의 연쇄 호출로 구성하는 현대적 스타일
예시 (JavaScript):
|
|
내부 클래스 기반 Builder (Effective Java 스타일)
설명: Product 클래스 안에 static Builder
클래스를 중첩하여 구성
예시 (JavaScript 유사):
|
|
Step Builder (타입 안전 빌더)
설명: 필수 단계를 순차적으로 강제하는 빌더, 컴파일 타임 타입 안정성 확보에 유리
예시 (TypeScript 스타일):
|
|
Functional Builder (Python DSL)
설명: 함수형 스타일로 빌더를 구성. 빌더 함수들을 조합하여 최종 객체 구성.
예시 (Python):
|
|
장점
카테고리 | 항목 | 설명 |
---|---|---|
1. 코드 구조 및 가독성 | 코드 가독성 향상 | 플루언트 인터페이스 및 체이닝 방식으로 직관적이고 읽기 쉬운 코드 작성 가능 |
클라이언트와 생성 로직 분리 | 클라이언트는 최종 객체에만 집중하고, 생성 과정은 빌더 내부로 숨겨 캡슐화 | |
유연한 객체 표현 | 동일한 빌더로 다양한 속성 조합의 객체 생성 가능 | |
2. 복잡성 관리 | 복잡한 객체 생성 단순화 | 단계별 생성 절차 분리로 인해 복잡한 생성 과정도 명확하게 관리 가능 |
복잡한 객체 구성 관리 | 선택적 속성, 중첩 구조 등 복잡한 객체 조합을 체계적으로 처리할 수 있음 | |
3. 안전성 및 불변성 | 매개변수 순서 독립성 | 생성자와 달리, 속성 설정 순서에 의존하지 않아 가독성과 안정성 향상 |
불변 객체 생성 보장 | 모든 속성 설정 후 객체 생성 → 변경 불가능한 객체로 스레드 안전성 확보 | |
객체 불완전성 방지 | build() 호출을 통해 모든 필드가 세팅되었는지 검증 가능 | |
유효성 검증 중앙화 | 생성 로직 내에서 일괄적으로 필드 검증 가능 (필수 조건 누락 방지 등) | |
4. 확장성과 유지보수성 | 확장성 | 새로운 속성이나 유형의 빌더를 추가하더라도 기존 코드 영향 없이 확장 가능 |
재사용성 | 빌더 구성 로직의 모듈화로 공통 패턴의 재사용이 가능, 코드 중복 감소 |
단점과 문제점 및 해결방안
단점
카테고리 | 단점 항목 | 설명 | 해결 방안 |
---|---|---|---|
설계 복잡도 | 클래스 수 증가 | Builder , Director , Product 등 구성 요소로 인한 클래스 수 증가 | 자동 생성 도구 (Lombok, CodeGen) 활용, 필요한 경우에만 도입 |
코드 복잡성 증가 | 단순한 객체에도 Builder 적용 시 코드 구조가 오히려 복잡해짐 | 기준 마련 (예: 매개변수 4 개 이상), 간단한 객체엔 생성자/팩토리 사용 | |
리소스 사용 | 성능 오버헤드 | 메서드 체이닝, 중간 객체 생성 등으로 인한 성능 저하 | 인라인 최적화, Lightweight Builder, 불필요한 체이닝 최소화 |
메모리 사용량 증가 | 빌더 객체 및 중간 상태 값 저장으로 인한 GC 부하 | 빌더 재사용 시 초기화 메서드 추가, 빌더 수명 관리 | |
검증/안정성 | 런타임 오류 가능성 | 필수 필드 누락, 잘못된 필드 순서 등으로 인한 런타임 오류 발생 가능 | @NonNull , 타입 힌트, Step Builder 등으로 컴파일 타임 검증 강화 |
적용 한계 | 과도한 설계 | 간단한 객체까지 과도하게 적용되면 오히려 오버엔지니어링 | 적용 기준 명확화, 단일 속성 객체엔 일반 생성자나 팩토리 활용 |
문제점
카테고리 | 문제 항목 | 원인 | 영향 | 탐지/진단 | 예방 방법 | 해결 기법 |
---|---|---|---|---|---|---|
상태 관리 | 빌더 상태 오염 | 빌더 인스턴스 재사용 시 이전 상태가 남아 있음 | 잘못된 객체 생성 | 단위 테스트, 상태 점검 로직 | 빌더 재사용 금지, 상태 초기화 로직 구현 | reset() , Immutable Builder 도입 |
중간 상태 노출 | build() 호출 전 객체를 외부에서 참조 가능 | 불완전한 객체 사용 | 상태 접근 제한 분석 | build() 후에만 객체 반환 | deep copy , immutable copy 적용 | |
유효성 및 안정성 | 필수 필드 누락 | 체이닝 방식에서 누락된 필수 필드에 대한 검증 부재 | 런타임 예외 발생 | 필드 null 체크, 빌더 사용 로그 분석 | 필수 필드 구분, 체이닝 강제 순서 구현 | Step Builder , Required Field Validator 적용 |
부분 객체 생성 | 모든 필드를 세팅하지 않아 불완전한 상태의 객체 생성됨 | 잘못된 결과 반환 | 런타임 검증, QA 시나리오 확인 | build() 내 유효성 검사 | Fluent Validation, assertComplete() 메서드 추가 | |
설계 일관성 | Director 의존성 과도 | Builder 사용 시 Director 가 빌드 순서를 강제하게 됨 | 설계 유연성 저하 | 역할 분석, 코드 리뷰 | 단순 빌더는 Client 에서 직접 체이닝 | Director 제거 또는 단일 빌더 방식 사용 |
재사용성 | 유사한 빌더 클래스 중복 | 도메인마다 유사한 빌더가 반복 구현됨 | 유지보수 부담, 코드 중복 증가 | 코드 중복 분석 도구 | 추상 Builder 설계, Generic Builder 사용 | Builder Registry/Template 적용 |
DI 통합 문제 | 의존성 주입 복잡화 | DI 컨테이너가 Builder 인스턴스를 관리하지 못하거나 조합 어려움 | 객체 생성 흐름 분리 | DI 로그 분석, 초기화 에러 추적 | Factory + Builder 패턴 조합 | Spring Bean Factory 안에 빌더 감싸기 |
도전 과제
카테고리 | 도전 과제 | 원인 | 영향 | 해결 방안 |
---|---|---|---|---|
아키텍처/설계 | 과도한 클래스 수 증가 | Director , Builder , ConcreteBuilder 등의 구조적 구성요소 다수 | 유지보수 복잡성 증가 | 단순한 경우 Director 생략, 내부 정적 Builder 사용 |
역할 분리 모호성 | Builder , Director , Client 간 책임 불명확 | 설계 일관성 저하 | 단일 책임 원칙 적용 (SRP), 역할 명확히 구분 | |
Product 변경 시 Builder 동기화 필요 | Product 필드 변경이 Builder 에 즉각 영향 | 동기화 누락 시 런타임 오류 발생 | 테스트 자동화, Code Generation 도구 (Lombok 등) 활용 | |
재사용성/중복 | 빌더 클래스 중복 | 유사한 도메인 객체마다 Builder 를 각각 구현 | 코드 중복 증가 | 공통 추상 Builder 또는 Generic Builder 패턴 도입 |
생성 로직 재사용 어려움 | 각 Builder 마다 로직이 캡슐화되어 있음 | 중복된 구현 증가 | 빌더 상속 구조 도입, Builder Pooling or Registry 설계 적용 | |
성능/자원 최적화 | 메모리 사용량 증가 | 빌더 객체 생성, 불변성 확보를 위한 중간 객체 누적 | GC 압박, 메모리 낭비 | 빌더 객체 재사용, 약한 참조 (WeakRef), Object Pooling |
빌더 호출 오버헤드 | 체이닝에 따른 메서드 호출 스택 증가 | 생성 속도 저하 | 인라인 최적화, 가벼운 빌더 도입 (Lightweight Builder) | |
객체 중복 생성 | 빌더와 최종 객체 간 데이터 중복 | 리소스 낭비 | Copy-on-write 방식, Prototype 패턴 결합 | |
타입 안전성 | 필수 필드 누락 위험 | 체이닝 방식은 선택적 필드와 구분이 어려움 | 객체 상태 불완전 | Step Builder, Required Field Check, @NonNull, IDE 지원 |
테스트/검증 | 유효성 검사 누락 | build() 호출 전 상태가 유효한지 보장되지 않음 | 예외 발생, 논리 오류 | build() 내부에 필드 조합 검증 로직 추가, Fluent Validation 기법 적용 |
테스트 작성 복잡성 | 복잡한 체이닝 로직 테스트 어려움 | 테스트 품질 저하 | Test Data Builder 패턴 활용, 각 빌더 단계별 유닛 테스트 설계 | |
현대 기술 환경 | MSA 환경에서 빌더 일관성 유지 어려움 | 서비스 간 DTO 생성 방식 불일치 | 인터페이스 불일치, 유지보수 어려움 | 공통 Builder 모듈화 (Shared Library), OpenAPI 기반 코드 생성 도입 |
클라우드 환경의 메모리 제한 | 서버리스/컨테이너 환경에서 오버헤드 민감 | 비용 증가, 성능 저하 | Lightweight Builder, Builder 객체 풀링 적용 | |
함수형 프로그래밍과의 충돌 | 가변 상태 관리 불가, 불변성 요구 | 전통 빌더 적용 곤란 | Immutable Builder, Functional Builder (람다/함수 조합 기반 빌더) 도입 | |
문서화/가독성 | 체이닝 순서 불명확 | 빌더 사용법이 직관적이지 않음 | 오용 위험, 디버깅 어려움 | JavaDoc/TSDoc 활용, IDE 용 Docstring 주석 및 예시 추가 |
빌더 사용법 표준 부재 | 팀 간 작성 방식 상이 | 코드 스타일 혼란 | 팀별 빌더 작성 가이드 수립, 코딩 컨벤션 포함 |
분류에 따른 종류 및 유형
분류 기준 | 유형 | 설명 | 주요 사용 사례 |
---|---|---|---|
구현 방식 | Classic (GoF) Builder | Director , Builder , Product 로 구성된 전통적 구조 | 복잡한 객체 생성 로직, 파서/컴파일러 등 |
Fluent Builder | 메서드 체이닝 기반 선언형 빌더 (.withX().withY().build() ) | API 클라이언트, 설정 객체, REST 요청 빌더 등 | |
Step Builder | 단계별 인터페이스로 강제 흐름 설계, 타입 안전성 강화 | 필수 필드가 많은 복잡 객체, 오류 방지 필요 시 | |
Lombok @Builder | 애노테이션 기반 빌더 자동 생성 | Java DTO, Config 클래스 등 | |
Effective Java Builder | 내부 정적 클래스를 활용한 실용적 빌더 구조 | Immutable 객체 생성 | |
복잡도 | Simple Builder | 단일 객체, 비교적 필드가 적은 경우에 적합 | Value Object, 단순 DTO |
Complex Builder | 유효성 검사, 조건부 조합 등 복잡한 로직 포함 | 도메인 객체, 설정 객체 | |
Composite Builder | 다수의 하위 요소 조합으로 구성된 복합 객체 생성 | UI 컴포넌트, 문서 생성, Aggregates | |
타입 안전성 | Basic Builder | 일반적인 빌더, 순서 제한 없음 | 일반 객체 빌더 |
Step Builder | 각 단계마다 다른 타입 반환으로 순서 강제 | 데이터 누락 방지, 안전성 우선 객체 | |
Generic Builder | 제네릭 기반으로 다양한 타입의 객체를 안전하게 구성 | 다양한 템플릿 객체 생성 시 | |
사용 범위 | Internal Builder | Product 클래스 내부에 정적 Builder 클래스를 정의 | 클래스 전용 빌더 |
External Builder | 독립된 외부 클래스에서 Builder 정의 | 공유/확장 가능한 빌더 구조 | |
Domain-Specific Builder | 특정 도메인에 최적화된 빌더 (예: DSL, SQL 쿼리 등) | QueryDSL, Flutter 위젯 구성 등 | |
구조 스타일 | Director 기반 | Builder 호출 순서를 캡슐화하는 Director 존재 | 전통적 GoF 구조에서 사용 |
No Director | Client 가 Builder 직접 호출 | 유연성과 단순성 중시 구조 | |
응용 형태 | Function Composition | 함수형 언어에서 빌더 기능을 함수 조합 형태로 표현 | Python, Kotlin 등 함수형 스타일 구성 시 |
DSL 기반 Builder | 선언형 Domain-Specific Language 형태로 객체 구성 | Kotlin DSL, Gradle, Terraform 설정 등 | |
생성 대상 | Single Product Builder | 하나의 객체만 생성 | 일반 객체 생성 |
Multi Product Builder | 다양한 변형 객체 또는 복수 객체를 생성 | 조건별 메시지, UI 템플릿 등 |
실무 사용 예시
카테고리 | 적용 분야 | 구체적 사용 예시 | 설명 및 효과 |
---|---|---|---|
백엔드 개발 | DTO/VO 생성 | API 요청/응답 객체, 설정 객체 등 | 필수/선택 필드 구분, 불변 객체 생성, 코드 가독성 향상 |
API 개발 | HTTP Request/Response | Retrofit, OkHttp, RestTemplate | 다양한 옵션의 요청/응답 객체 구성, 유연한 파라미터 설정 |
데이터베이스 | SQL Query 생성 | QueryDSL, JPA Criteria API, MyBatis, Jooq | 동적 SQL 쿼리 조합, 복잡한 쿼리 작성의 안정성과 가독성 확보 |
설정 관리 | 설정 객체 빌더 | Spring Boot 설정 객체, Docker 설정 | 환경별 설정 값 분리 및 설정 객체화, 유효성 검사 포함 가능 |
UI 개발 | UI 컴포넌트 생성 | React JSX, Flutter Widget, Android Dialog | 다양한 속성을 조합한 복합 위젯 생성, 선언적 구성 방식, 재사용성 확보 |
문서 생성 | 텍스트/HTML 문서 생성 | MarkdownBuilder, HTMLBuilder | 다양한 포맷의 문서를 공통 로직으로 단계별 구성 가능 |
테스트 | 테스트 데이터 구성 | Test Data Builder, Fixture Object | 다양한 테스트 상태의 객체 손쉽게 생성, 테스트 코드 가독성 및 유지보수성 향상 |
게임 개발 | 캐릭터/오브젝트 생성 | RPG 캐릭터 빌더, 속성 + 스킬 + 장비 조합 시스템 | 조건 기반의 복잡한 객체 생성 로직 구성 가능 |
메시징 시스템 | 메시지 객체 생성 | Kafka, RabbitMQ, Custom Message Builder | 메시지 헤더, 바디 구성 등 메시지 형식 표준화 및 직관적 구성 |
빌드 시스템 | 빌드 스크립트 구성 | Gradle, Maven DSL, Code Generator | 선언형 DSL 스타일 빌더 사용, 설정 코드 가독성 향상 |
기타 자동화 | 환경 구성 스크립트 | Infrastructure-as-Code DSL | 구성 요소 단계적 빌드, 재사용 및 조건부 구성 편의 제공 |
활용 사례
사례 1: 전자상거래 주문 시스템
시스템 구성:
활용 시나리오:
온라인 쇼핑몰에서 복잡한 주문 생성 과정을 Builder Pattern 으로 구현:
Workflow:
- 주문 초기화: 고객 정보와 기본 설정
- 상품 추가: 구매할 상품 목록 설정
- 배송 정보: 주소와 배송 옵션 설정
- 결제 정보: 결제 방법과 할인 적용
- 최종 검증: 주문 데이터 유효성 검사
- 주문 생성: 완성된 Order 객체 반환
사례 2: User Registration 요청 처리 시스템
요구 사항:
- 사용자 생성 시
username
,password
,email
은 필수 address
,phone
,marketingConsent
는 선택
구성 요소:
|
|
Workflow:
- 컨트롤러에서
User.Builder(username, password, email)
시작 - 옵션 필드에 따라
.address()
,.phone()
등 체이닝 build()
호출로 User 객체 생성
사례 3: 문서 생성
설명: Builder Pattern 은 복잡한 객체를 단계별로 생성하는 데 사용되며, 예를 들어 다양한 형식의 문서 생성에 활용된다.
시스템 구성:
- Director, Builder, ConcreteBuilder, Product
작동 방식:
- Director 가 Builder 를 통해 객체 생성 단계를 호출하고, ConcreteBuilder 가 구체적 객체를 생성한다.
차이점:
- 패턴 미적용 시 생성 로직이 클라이언트에 노출되어 유지보수 어려움
- 패턴 적용 시 생성 과정 캡슐화로 유연성 증가
|
|
구현 예시
시스템 구성: Spring Security 에서는 웹 보안 설정을 위해 Builder Pattern 을 광범위하게 활용한다.
graph TB A[HttpSecurity] --> B[AuthorizeHttpRequestsConfigurer] A --> C[FormLoginConfigurer] A --> D[CsrfConfigurer] A --> E[SessionManagementConfigurer] B --> F[AuthorizationFilter] C --> G[UsernamePasswordAuthenticationFilter] D --> H[CsrfFilter] E --> I[SessionManagementFilter] style A fill:#e3f2fd style B fill:#f3e5f5 style C fill:#e8f5e8 style D fill:#fff3e0 style E fill:#fce4ec
활용 사례 Workflow:
flowchart TD A[Spring Security Configuration] --> B[HttpSecurity Builder 생성] B --> C[authorizeHttpRequests 설정] C --> D[formLogin 설정] D --> E[csrf 설정] E --> F[sessionManagement 설정] F --> G[build 메서드 호출] G --> H[SecurityFilterChain 생성] H --> I[필터 체인 등록] style A fill:#e1f5fe style H fill:#e8f5e8 style I fill:#f3e5f5
Builder Pattern 의 역할:
- 설정 단계 분리: 각 보안 기능별로 독립적 설정
- 유연한 조합: 필요한 보안 기능만 선택적 적용
- 체인 방식: 메서드 체이닝으로 직관적 설정
- 타입 안전성: 컴파일 타임에 설정 오류 검출
Spring Security 사례를 바탕으로 한 보안 설정 빌더를 Python 과 Javascript 로 구현
Python
|
|
Javascript
|
|
실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점
카테고리 | 고려 항목 | 설명 | 권장사항 |
---|---|---|---|
적용 판단 기준 | 객체 복잡도 판단 | 매개변수 수, 조건 분기, 설정 조합이 많을 때에만 적용 | 매개변수 4 개 이상 또는 선택 필드가 많을 경우 사용 |
간단 객체에의 남용 방지 | 단순한 객체에 사용 시 코드 오버헤드 발생 | 간단한 경우 생성자나 정적 팩토리 메서드로 대체 | |
설계 원칙 | SRP 및 책임 분리 유지 | 빌더가 생성 외 기능 (유효성, 상태 저장 등) 을 갖게 되면 단일 책임 원칙 위배 | 생성, 상태 관리, 검증 책임은 각각 분리 |
인터페이스 일관성 | 빌더 체이닝/API 사용 방식이 프로젝트마다 다르면 혼란 유발 | 코딩 컨벤션 및 빌더 설계 가이드 마련 | |
클래스 수 증가 관리 | Product, Builder, Director 등 클래스가 증가할 수 있음 | Lombok @Builder , 코드 생성기 활용 | |
객체 일관성 및 유효성 | 필수/선택 필드 명확 구분 | 필수 필드 누락 시 잘못된 객체 생성 가능성 있음 | 생성자에 필수값, 체이닝에 선택값 배치 |
build() 시 유효성 검증 | 중간 상태에서의 불완전 객체 방지 필요 | build() 에서 모든 필드 조합 검증 또는 유효성 로직 포함 | |
불변성 보장 | 생성된 객체가 변경되면 안정성 및 예측성 저하 | 모든 필드 final , setter 제거, Immutable 객체 반환 | |
테스트 및 유지보수 | 테스트 데이터 생성 | 테스트 시 다양한 상태의 객체 필요 | Test Data Builder 패턴 활용, 단위 테스트 분리 |
Product 와 Builder 간 구조 동기화 | Product 구조 변경 시 빌더도 함께 수정 필요 | 자동화 툴 사용 또는 Product 기반 코드 생성 적용 | |
변경 영향도 관리 | 빌더 인터페이스 변경 시 다른 코드에 미치는 영향 존재 | 하위 호환성 고려 설계, 인터페이스 분리 적용 | |
성능 최적화 | 메모리 사용량 | Builder 는 일시적인 객체로 GC 부담 증가 가능 | 풀링, 재사용 가능 구조 설계 또는 빌더 리셋 메서드 구현 |
체이닝 오버헤드/지연 생성 | 불필요한 객체 생성이나 호출 순서 오류 발생 가능 | Lazy Initialization, 체이닝 최적화 | |
클래스 동기화/성능 이슈 | 멀티스레드 환경에서 공유 시 안전성 문제 | Thread-Safe Builder 혹은 복사 전략, ThreadLocal 적용 | |
문서화 및 가독성 | API 사용법 명시 | 체이닝 순서나 필수 메서드 등 문서가 부족할 경우 오용 위험 | IDE 인텔리센스 지원 + JavaDoc/TSDoc 주석 활용 |
가독성 향상 | 체이닝이 지나치게 길거나 복잡할 경우 가독성 저하 | 명확한 메서드 명명, 단계별 메서드 분리, Fluent API 설계 | |
팀 적용 관점 | 교육 및 패턴 숙지 필요 | 개발자마다 빌더 사용 방식이 상이할 수 있음 | 팀 가이드라인 수립, 내부 교육 또는 코드 리뷰 강화 |
팀 표준화/자동화 적용 | 공통 빌더 템플릿 또는 도구 활용 필요 | Lombok, Kotlin DSL, 코드 생성기 도입 검토 |
6.23 테스트 전략
단위 테스트 접근법:
|
|
6.24 리팩토링 전략
기존 생성자를 Builder 로 리팩토링:
- 1 단계: 기존 생성자 유지하면서 Builder 추가
- 2 단계: 클라이언트 코드를 점진적으로 Builder 로 전환
- 3 단계: 기존 생성자를 Deprecated 처리
- 4 단계: 기존 생성자 제거 및 Builder 전용화
리팩토링 체크리스트:
- 매개변수 4 개 이상의 생성자 식별
- 선택적 매개변수가 있는 생성자 확인
- 불변 객체 전환 필요성 평가
- 기존 클라이언트 코드 영향도 분석
- 단계적 전환 계획 수립
6.25 활용 시 흔한 실수
주요 실수 유형:
빌더 상태 오염
- 문제: 빌더 인스턴스 재사용 시 이전 상태 잔존
- 해결: 빌더 리셋 메서드 구현 또는 새 인스턴스 생성
불완전한 유효성 검증
- 문제: 빌드 시점이 아닌 사용 시점에 오류 발견
- 해결: build() 메서드에서 완전한 검증 수행
과도한 빌더 적용
- 문제: 단순한 객체에도 빌더 패턴 적용
- 해결: 복잡도 기준 수립 (매개변수 4 개 이상)
메모리 누수
- 문제: 빌더에서 참조하는 대용량 객체 미해제
- 해결: 빌드 완료 후 참조 정리
최적화하기 위한 고려사항 및 주의점
카테고리 | 최적화 항목 | 설명 | 권장사항 |
---|---|---|---|
성능 | 객체 생성 비용 | Builder 및 Product 객체 생성이 반복되면 비용 증가 | 팩토리 래핑, 캐싱, 불필요한 생성 최소화 |
메서드 체이닝 오버헤드 | 체이닝 방식이 성능에 영향을 줄 수 있음 | 인라인 최적화, 체이닝 최소화, 컴파일러 최적화 신뢰 | |
빌드 결과 캐싱 | 동일 빌드 입력에 대해 반복 생성 방지 | 결과 객체 캐싱 및 Flyweight 적용 가능 | |
메모리 최적화 | 빌더 객체 일시적 생성 | GC 에 부담이 될 수 있는 임시 객체 다수 생성 | 사용 후 참조 해제, reset 메서드 구현, 객체 풀 적용 |
불필요한 중간 객체 | 빌드 과정에서 불필요한 필드/객체 생성 발생 가능 | Lazy Initialization, Copy-on-Write, 중간 값 생략 전략 적용 | |
빌더 재사용성 | Stateless 하지 않으면 오작동 위험 있음 | 상태 없는 빌더로 구현하거나 풀링 전략 사용 | |
타입 안전성 | 체이닝 순서 의존성 | 필드 설정 순서가 잘못되면 런타임 오류 가능 | Step Builder, 필수 필드 강제, @NonNull, IDE 타입 힌트 사용 |
유효성 및 일관성 | build() 내부 검증 비용 | 유효성 로직이 복잡할수록 build() 호출 비용 증가 | 필수/선택 필드 구분, 유효성 최소화, 사전 검증 단계 분리 |
객체 상태 일관성 | build() 전 객체 상태 불완전 가능성 | 중간 상태 노출 방지, 불변 객체 반환, clone 기반 재생성 전략 | |
코드 품질 | 중복 빌더 구현 | 유사 객체마다 빌더가 중복 구현됨 | 추상 빌더 계층 도입, 공통 빌더 추상화 구조 사용 |
확장성 | 플러그인 기반 확장 | 기능 확장 시 빌더 구조 확장이 어렵거나 깨지기 쉬움 | 확장 포인트 인터페이스 도입, 인터셉터/Decorator 적용 가능 |
테스트 | 테스트 친화성 | 복잡한 빌더는 테스트하기 어려움 | 테스트 전용 빌더 제공, 빌더 상태 추적 기능 추가 |
배포/툴 통합 | 코드 생성 도구 활용 | 반복적인 빌더 구현은 유지보수에 부담됨 | Lombok @Builder , Kotlin DSL, Annotation Processor 활용 |
불변성 보장 | 상태 변경 허용 시 일관성 문제 | 불변성이 없으면 사이드 이펙트 발생 가능 | build() 결과는 Immutable Object 로 구성, 컬렉션은 불변 컬렉션으로 처리 |
주제와 관련하여 주목할 내용
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
설계 패턴 이해 | Builder Pattern | 객체 구성 | 생성 과정을 단계별로 분리하여 복잡한 객체 생성 지원 |
유연성 | 동일한 생성 절차로 다양한 객체 표현 가능 | ||
재사용성 | 생성 로직 재사용으로 코드 중복 감소 | ||
인터페이스 설계 | 단계별 메서드를 명확히 정의하여 명확한 계약 제공 | ||
Director | 객체 생성 과정을 조정하는 관리자 역할 | ||
ConcreteBuilder | 실제 객체 생성 로직 구현 클래스 | ||
불변성/타입 안전성 | Immutable Object | 빌더를 통한 불변 객체 생성 가능 | |
Phantom Types | 타입 시스템을 활용한 단계 안전 보장 (컴파일 타임 검증) | ||
프레임워크 활용 | Spring Framework | Spring Security HttpSecurity Builder | 보안 설정을 빌더 방식으로 구성 |
Spring Boot | Auto Configuration Builder | 자동 설정 시 빌더 스타일의 구성 적용 | |
Spring Core | BeanDefinitionBuilder | XML 없이 자바 코드로 Bean 구성 | |
언어/도구 기반 지원 | Lombok | @Builder 애노테이션 | 컴파일 타임에 빌더 코드를 자동 생성 |
Kotlin | Named Parameters + DSL | 빌더 없이도 선언형 방식으로 객체 구성 가능 | |
Gradle | Build Script DSL | 선언형 DSL 스타일로 빌드 스크립트 구성 | |
웹/클라이언트 개발 | HTTP Client | OkHttp, Retrofit | REST API 요청 구성을 위한 빌더 구조 활용 |
React (JSX) | Component Builder | 컴포넌트 구성 시 빌더 스타일 패턴 적용 | |
데이터 처리/DB | Query Builder | JPA Criteria API | 동적 쿼리를 위한 빌더 기반 DSL 구성 |
JSON/XML Builder | 문서 생성 DSL | JSON, XML 구조 생성을 위한 빌더 패턴 적용 | |
테스트 전략 | Test Data Builder | 테스트 객체 구성 자동화 | 테스트 전용 객체 생성 시 코드 간결화와 재사용성 확보 |
도메인 모델링 | DDD Builder | Aggregate Builder | 복잡한 애그리게이트 객체 생성 시 빌더 활용 |
함수형/반응형 프로그래밍 | Functional Builder | 함수형 빌더 구현 | 람다와 클로저 기반 선언형 빌더 구조 구현 |
Reactive Builder | 비동기 빌더 | RxJava, WebFlux 등과 결합하여 반응형 흐름에 적합한 빌더 적용 | |
성능 최적화 | Zero-Copy Builder | 메모리 복사 제거 | 메모리 오버헤드 없이 객체 구성 |
Builder Pool Pattern | 빌더 객체 재사용 | 풀링을 통한 메모리 및 생성 비용 절감 | |
검증/안전성 | Validation Builder | build 시 검증 | 객체 생성 전 유효성 검증 내장 가능 |
패턴 간 비교/조합 | Abstract Factory vs Builder | 생성 방식 비교 | 제품군 vs 복잡 조립 차이 구분 |
Prototype vs Builder | 복제 vs 조립 | 생성 전략의 목적 차이에 따른 적합성 판단 | |
Builder + Prototype | 복사 + 조립 조합 | 공통 기본 틀 복사 후 빌더로 커스터마이징 |
추가 학습 내용
카테고리 | 주제 | 설명 |
---|---|---|
기본 개념 | Builder Pattern (GoF) | 객체 생성 과정을 단계별로 분리하여 다양한 표현을 가능하게 하는 생성 패턴 |
Director | 생성 과정을 조정하여 일관된 절차로 제품을 생성하는 역할 | |
ConcreteBuilder | 실제 생성 로직을 정의하는 구체적인 빌더 구현체 | |
Product | 빌더가 생성하는 최종 결과 객체 | |
고급 구조 | Step Builder Pattern | 생성 순서를 타입 시스템으로 강제하여 타입 안전성을 확보하는 빌더 구조 |
내부/외부 Builder | 내부 클래스 또는 외부 클래스로 빌더를 구현하는 방식 차이 | |
Fluent Interface | 메서드 체이닝을 통해 선언적이고 가독성 높은 API 를 설계하는 방식 | |
Method Chaining | 객체 생성 과정을 연속된 메서드 호출로 연결하는 구현 기법 | |
성능 최적화 | Builder Pool Pattern | Builder 인스턴스를 풀링하여 재사용함으로써 객체 생성을 최적화 |
Memory-Efficient Builder | 불필요한 객체 생성을 줄이고 메모리 효율을 높이기 위한 전략 | |
함수형 접근 | Functional Builder | 람다 표현식, 클로저 등을 활용한 선언적 빌더 구현 방식 |
동시성 | Thread-Safe Builder | 멀티스레드 환경에서도 안전하게 사용할 수 있도록 동기화된 빌더 설계 |
테스트 전략 | Test Data Builder | 테스트에 필요한 객체 생성을 자동화하고 반복 코드 제거 |
Fixture Builder | 테스트 고정 데이터 (Fixture) 를 빌더로 구성하는 방식 | |
도메인 모델링 | Aggregate Builder | DDD 에서 복잡한 애그리게이트 객체 생성을 담당하는 빌더 구조 |
설정/DTO 빌더 | 설정 파일, DTO 객체 등의 생성 시 빌더 패턴을 활용한 실무 예제 | |
API 설계 | Fluent API | 자연어에 가까운 표현으로 직관적인 API 를 설계하는 기법 |
생성 패턴 비교 | Factory vs Builder | 제품군 생성 (Factory) vs 복잡한 객체 조립 (Builder) 의 책임 분리 비교 |
Prototype vs Builder | 객체 복제 중심 (Prototype) 과 조립 중심 (Builder) 의 차이 비교 | |
불변 객체 설계 | Immutable Object + Builder | 생성 후 상태가 바뀌지 않는 객체의 안전한 빌더 조합 방식 |
프레임워크/자동화 도구 | Lombok, Kotlin DSL | Java/Kotlin 에서 빌더 자동 생성 및 선언형 DSL 스타일 빌더 구현 방법 |
코드 생성기 | 빌더 코드 생성을 자동화하는 도구 사용법 (예: Swagger Codegen, Lombok 등) | |
DSL 및 구성 도구 | SQL DSL (JOOQ, QueryDSL) | 빌더 기반 DSL 로 SQL 쿼리를 안전하고 선언적으로 생성하는 도구 |
JSON/XML Builder | JSON, XML 등 문서 구조 생성을 위한 빌더 기반 파서 설계 | |
UI Builder (React, Flutter) | 선언형 UI 프레임워크에서의 빌더 패턴 활용 방식 | |
소프트웨어 원칙 | SRP (단일 책임 원칙) | 빌더 클래스는 객체 생성 책임만 가지도록 구성 |
설계/품질 원칙 | Clean Code | 빌더 패턴을 활용한 가독성 높은 설계와 유지보수 중심 개발 철학 적용 |
성능/메모리 관리 | Object Pooling | 빌더/생성 객체 재사용을 통한 메모리 오버헤드 최소화 |
학습 필수 요소 | GoF 23 패턴 | 전체적인 디자인 패턴 체계 내에서 Builder 의 위치 이해 |
SOLID | 빌더 패턴의 구조적 설계를 위한 객체지향 원칙 기반 분석 | |
아키텍처 전략 | CQRS + Builder | Command 객체 생성을 위한 빌더 패턴 결합 전략 |
Domain-Driven Design | 복잡한 도메인 모델에서 빌더를 활용한 객체 생성 전략 |
용어 정리
카테고리 | 용어 | 설명 |
---|---|---|
패턴 구성요소 | Builder | 객체 생성 단계 (메서드) 를 정의하는 추상 인터페이스 또는 베이스 클래스 |
ConcreteBuilder | Builder 를 구현하며 실제 Product 를 생성하는 클래스 | |
Director | Builder 의 메서드를 호출하여 객체 생성 순서를 제어하는 관리자 역할 클래스 (선택적) | |
Product | 빌더 패턴을 통해 최종적으로 생성되는 복잡한 객체 | |
설계 기법 | Fluent Interface | 메서드 체이닝을 통해 선언적·가독성 높은 API 를 구성하는 인터페이스 스타일 |
Method Chaining | 각 메서드가 자기 자신을 반환하여 연속적으로 호출 가능하게 하는 기법 | |
Step Builder | 각 단계마다 다른 인터페이스를 반환하여 빌드 순서를 강제하고 컴파일 타임 검증 제공 | |
프로그래밍 개념 | Immutable Object | 한 번 생성된 후 내부 상태가 변경되지 않는 객체로, 안정성과 예측 가능성 제공 |
Telescoping Constructor | 생성자 매개변수가 점점 늘어나는 안티패턴으로, 빌더 패턴이 이를 해결 | |
최적화 기법 | Object Pooling | 생성된 객체를 재사용하여 메모리 및 성능을 최적화하는 기법 |
참고 및 출처
- Refactoring.Guru – Builder Pattern 설명
- Builder Pattern - GeeksforGeeks Java 구현
- Builder Pattern in Java - DigitalOcean
- Builder Pattern - Tutorialspoint
- Builder Pattern Example - Java Code Geeks