Hello

[디자인 패턴] - Builder

by 볼빵빵오춘기

Builder 패턴

복잡한 객체의 생성 과정을 단계별로 나누고, 최종적으로 객체를 조립하여 생성하는 패턴이다.

즉, 객체의 생성 과정과 표현 방법을 분리하여, 동일한 생성 과정에서도 다양한 형태의 객체를 만들 수 있도록 도와준다.

 

예제 코드

// 1. Product (복잡한 객체)
class Computer {
    private String CPU;
    private String RAM;
    private String storage;
    private boolean hasGraphicsCard;
    
    // private 생성자 (객체 직접 생성 불가, Builder를 통해 생성)
    private Computer(Builder builder) {
        this.CPU = builder.CPU;
        this.RAM = builder.RAM;
        this.storage = builder.storage;
        this.hasGraphicsCard = builder.hasGraphicsCard;
    }
    
    @Override
    public String toString() {
        return "Computer [CPU=" + CPU + ", RAM=" + RAM + ", Storage=" + storage + 
               ", Graphics Card=" + hasGraphicsCard + "]";
    }

    // 2. Builder (내부 정적 클래스)
    public static class Builder {
        private String CPU;
        private String RAM;
        private String storage;
        private boolean hasGraphicsCard;

        public Builder(String CPU, String RAM) { // 필수 속성 설정
            this.CPU = CPU;
            this.RAM = RAM;
        }

        public Builder setStorage(String storage) {
            this.storage = storage;
            return this;
        }

        public Builder setGraphicsCard(boolean hasGraphicsCard) {
            this.hasGraphicsCard = hasGraphicsCard;
            return this;
        }

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

// 3. Client 코드 (사용 예제)
public class BuilderExample {
    public static void main(String[] args) {
        // 필수 속성만 지정
        Computer basicComputer = new Computer.Builder("Intel i5", "8GB").build();
        System.out.println(basicComputer);

        // 추가 옵션 포함
        Computer gamingComputer = new Computer.Builder("Intel i9", "32GB")
                                    .setStorage("1TB SSD")
                                    .setGraphicsCard(true)
                                    .build();
        System.out.println(gamingComputer);
    }
}

 

Builder 패턴의 장점

가독성 향상

객체 생성 코드가 단계별로 명확하게 구성되어 있어 이해하기 쉽다.

new Computer("Intel i7", "16GB", "512GB SSD", true);

가독성이 낮다.

 

new Computer.Builder("Intel i7", "16GB").setStorage("512GB SSD").setGraphicsCard(true).build();

가독성이 높다.

 

객체 생성의 유연성

필요에 따라 선택적인 속성을 설정할 수 있다.

ex) setGraphicsCard()를 호출하지 않으면 기본값(false) 유지한다.

 

불변 객체(Immutable Object) 생성 가능

private 생성자와 Builder를 사용하면 객체가 불변(Immutable)하게 설계될 수 있다.

 

생성자의 오버로딩 문제 해결

기존 생성자 방식에서는 다양한 조합을 위해 여러 개의 생성자를 만들어야 하지만, Builder 패턴을 사용하면 불필요한 생성자 오버로딩을 방지할 수 있다.

 

일관성 유지

클라이언트가 잘못된 객체를 생성하는 실수를 방지할 수 있음.

ex) 필수 속성을 Builder 생성자로 강제할 수 있다.

 

Builder 패턴의 단점

코드가 복잡해질 수 있다.

단순한 객체 생성에는 필요 없는 코드(Builder 클래스, setter 메서드 등)가 추가된다.

ex) Computer.Builder를 만들어야 하므로, 코드가 다소 길어진다.

 

객체 생성 비용 증가

Builder 객체를 추가로 생성해야 하므로, 메모리 사용량이 증가할 수 있다.

(But 대부분의 경우 무시할 수 있을 정도로 미미한 단점이다.)

 

빌더를 변경하면 관련 코드도 수정해야 함

Builder가 변경될 경우, 이를 사용하는 모든 코드에 영향을 미칠 수 있다.

 

 

 

Builder 패턴을 언제 사용할까?

객체의 속성이 많거나 조합이 다양할 때

ex) 컴퓨터, 자동차, 사용자 계정 등 다양한 옵션을 설정할 수 있는 객체.

 

생성자의 오버로딩이 너무 많을 때

Person(String name), Person(String name, int age), Person(String name, int age, String address), …
Builder 패턴으로 개선 가능.

 

객체가 불변(Immutable)해야 할 때

private final 필드와 함께 사용하면 불변 객체를 쉽게 생성할 수 있다.

 

객체 생성의 일관성을 유지하고 싶을 때

필수 속성을 강제할 수 있어 불완전한 객체 생성을 방지 가능

 

정리하자면

  • 복잡한 객체의 생성 과정을 명확하고 유연하게 관리할 수 있도록 도와주는 패턴이다.
  • 생성자의 오버로딩을 줄이고, 가독성을 높이며, 선택적인 속성을 추가할 수 있도록 해주는 것이 가장 큰 장점이다.
  • 단순한 객체에 사용하면 불필요한 코드가 많아질 수 있으므로, 적용할 필요가 없는 경우에는 일반적인 생성자 패턴을 사용할 수도 있다.

∴ 객체가 복잡하고 옵션이 많을 때는 Builder 패턴을 적극적으로 활용하면 좋은 선택이 될 수 있다!

블로그의 정보

Hello 춘기's world

볼빵빵오춘기

활동하기