1. 빌더 패턴(Builder Pattern)이란?

빌더 패턴은 복잡한 객체를 안전하고 명확하게 생성하기 위한 디자인 패턴입니다.
필수 값과 선택 값을 구분하며, 메서드 체이닝 방식으로 객체 생성 과정을 간결하게 표현할 수 있습니다.

빌더 패턴의 특징

  • 필수 값 지정: 반드시 필요한 값만 설정할 수 있도록 강제
  • 선택 값 유연성: 선택적으로 설정 가능하며, 설정하지 않으면 기본값이 유지
  • 불변성 보장: 생성된 객체는 필드 값이 변경되지 않도록 설계
  • 가독성 향상: 메서드 체이닝으로 설정 과정을 직관적으로 표현


2. 필수 값과 선택 값의 구분

1) 구분 기준

  • 필수 값: 빌더 클래스의 생성자에서 초기화가 강제된 필드. 빌더 객체를 생성할 때 반드시 값을 제공해야 합니다.
  • 선택 값: 빌더 클래스의 setter 메서드를 통해 설정되는 필드. 설정하지 않으면 기본값(예: 0, null)이 유지됩니다.

2) 코드에서의 구분

public class Computer {
    private final String cpu;  // 필수 값
    private final int ram;     // 선택 값
    private final int storage; // 선택 값
    private final String gpu;  // 선택 값

    private Computer(ComputerBuilder builder) {
        this.cpu = builder.cpu;         // 필수 값 초기화
        this.ram = builder.ram;         // 선택 값 초기화
        this.storage = builder.storage; // 선택 값 초기화
        this.gpu = builder.gpu;         // 선택 값 초기화
    }

    public static class ComputerBuilder {
        private final String cpu; // 필수 값
        private int ram;          // 선택 값
        private int storage;      // 선택 값
        private String gpu;       // 선택 값

        // 필수 값 설정 (생성자)
        public ComputerBuilder(String cpu) {
            this.cpu = cpu; // 필수 값 초기화
        }

        // 선택 값 설정 (setter 메서드)
        public ComputerBuilder setRam(int ram) {
            this.ram = ram;
            return this;
        }

        public ComputerBuilder setStorage(int storage) {
            this.storage = storage;
            return this;
        }

        public ComputerBuilder setGpu(String gpu) {
            this.gpu = gpu;
            return this;
        }

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

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram=" + ram + "GB" +
                ", storage=" + storage + "GB" +
                ", gpu='" + gpu + '\'' +
                '}';
    }
}

3) 동작 방식

  • 필수 값(cpu)은 빌더 생성자에서 설정되며 누락이 불가능합니다.
  • 선택 값(ram, storage, gpu)은 setter 메서드로 설정되며, 설정하지 않으면 기본값이 유지됩니다.


3. 빌더 패턴 사용

public class Main {
    public static void main(String[] args) {
        // 기본 컴퓨터
        Computer basicComputer = new Computer.ComputerBuilder("Intel i5")
                .setRam(8)
                .setStorage(256)
                .build();
        System.out.println("basicComputer = " + basicComputer);

        // 게이밍 컴퓨터
        Computer gamingComputer = new Computer.ComputerBuilder("AMD Ryzen 7")
                .setRam(32)
                .setStorage(1000)
                .setGpu("NVIDIA RTX 3080")
                .build();
        System.out.println("gamingComputer = " + gamingComputer);

        // 코딩용 컴퓨터
        Computer codingComputer = new Computer.ComputerBuilder("Intel i9")
                .setRam(64)
                .setStorage(512)
                .build();
        System.out.println("codingComputer = " + codingComputer);
    }
}

결과

basicComputer = Computer{cpu='Intel i5', ram=8GB, storage=256GB, gpu='null'}
gamingComputer = Computer{cpu='AMD Ryzen 7', ram=32GB, storage=1000GB, gpu='NVIDIA RTX 3080'}
codingComputer = Computer{cpu='Intel i9', ram=64GB, storage=512GB, gpu='null'}


4. Setter 방식과 비교

1) Setter 방식의 문제점

Setter를 사용하면 각 필드를 개별적으로 설정해야 하므로 코드의 일관성이 떨어지고, 필수 값 누락 위험이 있습니다.

2) Setter 방식 코드

public class Computer {
    private String cpu;
    private int ram;
    private int storage;
    private String gpu;

    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setRam(int ram) { this.ram = ram; }
    public void setStorage(int storage) { this.storage = storage; }
    public void setGpu(String gpu) { this.gpu = gpu; }

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram=" + ram + "GB" +
                ", storage=" + storage + "GB" +
                ", gpu='" + gpu + '\'' +
                '}';
    }
}

3) Setter 사용 예시

public class Main {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.setCpu("Intel i5");
        computer.setRam(8);
        computer.setStorage(256);
        computer.setGpu("NVIDIA RTX 3060");

        System.out.println("computer = " + computer);
    }
}


5. Setter와 Builder의 비교

특징 Setter 방식 Builder 패턴
필수 값 처리 필수 값 누락 가능 필수 값 설정을 강제
객체의 불변성 생성 후 필드 수정 가능 생성 후 필드 수정 불가
가독성 설정 코드가 분산됨 메서드 체이닝으로 명확하게 표현
유연성 설정 순서와 상관없이 필드를 수정할 수 있음 필요한 값만 선택적으로 설정 가능