빌더 패턴

이정석·2023년 6월 22일
0

디자인패턴

목록 보기
13/23
post-thumbnail

빌더 패턴이란?

객체를 만들기 위한 정보가 많을 때 일부 정보만 가지고 있다면 객체를 점진적으로 만들어 나가는 패턴으로 복잡한 객체를 단계적으로 구축하는 패턴이다.


문제상황

1. 다음과 같은 Coffee 클래스가 있다 하자.

public class Coffee {
    private String size;
    private String milk;
    private boolean mocha;
    private boolean whip;
    private boolean caramel;

    public Coffee(String size) {
        this(size, "No", false, false, false);
    }

    public Coffee(String size, String milk) {
        this(size, milk, false, false, false);
    }

    public Coffee(String size, String milk, boolean mocha) {
        this(size, milk, mocha, false, false);
    }

    public Coffee(String size, String milk, boolean mocha, boolean whip) {
        this(size, milk, mocha, whip, false);
    }

    public Coffee(String size, String milk, boolean mocha, boolean whip, boolean caramel) {
        this.size = size;
        this.milk = milk;
        this.mocha = mocha;
        this.whip = whip;
        this.caramel = caramel;
    }
}

커피의 옵션과 토핑에는 사이즈, 우유, 모카, 휘핑 등 많은 옵션들이 있고 각각의 옵션에 따라 여러개의 생성자가 있다.
2. Coffe를 만드는 Client코드는 다음과 같이 된다.

public class Client {
    public static void main(String[] args) {
    	Coffee coffee1 = new Coffee("Large");
		Coffee coffee2 = new Coffee("Medium", "Almond");
		Coffee coffee3 = new Coffee("Medium", "Soy", true, false, true);
   }
}

코드를 보면 각각의 생성자의 요구되는 매개변수와 해당하는 변수들이 무엇을 뜻하는지 알기 힘드며 새로운 옵션을 추가하기 위해서는 생성자를 추가해야 한다.


구조

  1. Director: Builder 인터페이스를 사용하는 클래스로 사용자의 요청을 받아 Product를 생성하도록 명령하는 클래스이다. Director를 사용하지 않고 Client가 직접 Builder를 사용할 수도 있다.
  2. Builder: Product를 생성하는데 필요한 인터페이스를 정의한 것으로 buildPart는 Product를 구축하는데 필요한 메소드를 정의한 것이다.
  3. ConcreteBuilder: Builder를 구현한 클래스로 최종 Product를 구성하는데 필요한 모든 메서드를 구현한다. getResult는 buildPart로 구축된 Product를 반한다.
  4. Product: 실제 생성되는 객체이다.

코드(JAVA)

1. Coffee

public class Coffee {
    private String size;
    private String milk;
    private boolean mocha;
    private boolean whip;
    private boolean caramel;

    public Coffee() {}

    public void setSize(String size) {
        this.size = size;
    }

    public void setMilk(String milk) {
        this.milk = milk;
    }

    public void setMocha(boolean mocha) {
        this.mocha = mocha;
    }

    public void setWhip(boolean whip) {
        this.whip = whip;
    }

    public void setCaramel(boolean caramel) {
        this.caramel = caramel;
    }
}

2. CoffeeBuilder

public class CoffeeBuilder {
    private Coffee coffee;

    public CoffeeBuilder(String size) {
        coffee = new Coffee();
        coffee.setSize(size);
    }

    public CoffeeBuilder milk(String milk) {
        coffee.setMilk(milk);
        return this;
    }

    public CoffeeBuilder mocha(boolean mocha) {
        coffee.setMocha(mocha);
        return this;
    }

    public CoffeeBuilder whip(boolean whip) {
        coffee.setWhip(whip);
        return this;
    }

    public CoffeeBuilder caramel(boolean caramel) {
        coffee.setCaramel(caramel);
        return this;
    }

    public Coffee build() {
        return coffee;
    }
}

3. Client

public class Client {
    public static void main(String[] args) {
      Coffee coffee = new CoffeeBuilder("Large").milk("Almond")
                          .whip(true).build();
   }
}

문제 상황과는 다르게 어떤 속성에 어떤 값이 매칭되는지 보기 쉽다.


필수 초기화 변수

빌더 패턴을 사용함으로 얻을 수 있는 효과 중 하나는 필수 초기화 변수초기화를 하지 않아도 되는 변수를 구분할 수 있다는 점이다. 위 예제로는 size필수 초기화 변수이고 나머지 가 초기화를 하지 않아도 되는 변수이다.

  • 필수 초기화 변수는 Builder 생성시에도 필요한 변수로, Builder를 생성할 때 값을 넘겨준다.
  • 초기화를 하지 않아도 되는 변수는 이후 Builder의 buildPart 메소드를 통해 Set해준다.
profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글