본문 바로가기

디자인 패턴/생성 패턴

[생성 패턴] 빌더 패턴 (Builder Pattern)

728x90

Builder Pattern이란?

  • 생성 디자인 패턴(Creational Design Pattern) 중 하나로, 복잡한 객체 생성을 단계적으로 수행할 수 있도록 돕는 패턴입니다.
  • 클래스가 많은 매개변수를 가지는 경우 객체 생성의 복잡성을 줄이고, 코드의 가독성을 높이는 데 유용합니다.
  • 여러 개의 생성자(다양한 매개변수 조합)를 작성하는 번거로움을 해소하며, 유연성과 확장성을 제공합니다.

 

Builder Pattern의 특징

  1. 유연한 객체 생성: 불필요한 생성자 오버로딩을 줄이고 원하는 값만 설정 가능.
  2. 가독성: 객체 생성 시 어떤 값을 설정하는지 명확히 알 수 있음.
  3. 불변성 유지: Builder를 통해 객체를 생성하면, 생성된 객체는 변경 불가능(immutable)하게 유지 가능.
  4. 확장성: 새로운 필드 추가 시 기존 코드 변경 없이 Builder에만 수정 가능.

 

기존 객체 생성 방식

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student("shs00925", 100); // 모든 필드 설정
        Student student2 = new Student("shs00925");      // 일부 필드만 설정
        Student student3 = new Student(100);             // 일부 필드만 설정

        System.out.println(student1);
        System.out.println(student2);
        System.out.println(student3);
    }
}

class Student {
    private String name;
    private int score;

    // 다양한 생성자
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public Student(String name) {
        this.name = name;
    }

    public Student(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "학생의 이름은 : " + name + " 성적은 " + score;
    }
}

문제점

  1. 생성자 오버로딩이 많아짐(매개변수 조합이 많을수록 더욱 복잡).
  2. 필드가 추가되면 모든 생성자를 다시 작성해야 함.
  3. 생성자 호출 시 값이 어떤 필드에 해당하는지 명확하지 않음.

 

 

Builder Pattern

public class Main {
    public static void main(String[] args) {
        // 기존 방식
        Student student1 = new Student("shs00925", 100);
        Student student2 = new Student("shs00925");
        Student student3 = new Student(100);

        // Builder Pattern 사용
        Student builderStudent = new Student.Builder()
                .name("shs00925") // 체이닝으로 필드 설정
                .score(100)
                .build();         // 최종적으로 객체 생성

        System.out.println(student1);
        System.out.println(student2);
        System.out.println(student3);
        System.out.println(builderStudent);
    }
}

class Student {
    private final String name; // 불변성을 유지하기 위해 final
    private final int score;

    // 생성자는 Builder를 통해서만 호출
    private Student(Builder builder) {
        this.name = builder.name;
        this.score = builder.score;
    }

    @Override
    public String toString() {
        return "학생의 이름은 : " + name + ", 성적은 : " + score;
    }

    // Builder 클래스
    public static class Builder {
        private String name; // 선택적으로 설정할 필드
        private int score;

        public Builder() {
        }

        // 각 필드를 설정하는 메서드
        public Builder name(String name) {
            this.name = name;
            return this; // 체이닝 지원
        }

        public Builder score(int score) {
            this.score = score;
            return this; // 체이닝 지원
        }

        // build 메서드로 최종 Student 객체 생성
        public Student build() {
            return new Student(this);
        }
    }
}

 

 

Builder Pattern의 장점

1. 가독성 : 각 필드가 어떤 값을 의미하는지 명확히 알 수 있음

2. 유연성 : 필드를 선택적으로 설정 가능

3. 확장성 : 새로운 필드 추가 시 Builder에만 새로운 메서드를 추가하면 됨. 기존 코드는 수정 불필요

4. 유연성 : Builder를 통해 생성된 객체는 final 필드를 가지므로 변경할 수 없음

 

 

Builder Pattern의 사용 사례

  • 복잡한 객체 생성: 데이터베이스 연결 설정, HTTP 요청 생성, 복잡한 UI 구성 등.
  • Immutable 객체 생성: 변경 불가능한 객체를 생성하고자 할 때.
  • 매개변수가 많은 클래스: DTO(Data Transfer Object)나 VO(Value Object)처럼 여러 필드를 가지는 객체.
728x90