Updated:

1. 개요

복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴

빌더 패턴(Builder Pattern)은 생성 패턴(Creational Pattern)의 한 종류로, 빌더 객체의 인터페이스를 통해 필요한 객체를 차례대로 전달하고, 전달 받은 객체들을 조합하여 하나의 완성된 객체를 반환해주는 패턴이다.

2. 생성 패턴(Creational Pattern)

2-1. 생성 패턴이란?

생성 패턴이란 인스턴스를 만드는 절차를 추상화하는 패턴으로, 객체를 생성, 합성하는 방법이나 객체의 표현 방법과 시스템을 분리해 준다. 생성 패턴은 아래 두 가지 특징으로 인해 무엇이, 어떻게, 언제 생성되는지 결정하는데 유연성을 확보할 수 있다.

  • 시스템이 어떤 구체 클래스를 사용하는지에 대한 정보를 캡슐화 한다.

  • 인스턴스들이 어떻게 만들고, 결합하는지에 대한 부분을 완전히 가려준다.

2-2. 생성 패턴 종류

3. 구성

[출처 : GoF의 디자인 패턴]

  • Builder : 객체의 요소들을 생성하기 위한 추상 클래스

  • ConcreteBuilder : Builder가 정의한 메서드 구현

  • Director : Builder 인터페이스를 사용하는 객체를 합성

  • Product : 생성할 복합 객체를 표현

4. 예제 코드

커피를 만드는 과정을 구현한다고 가정해보자. 커피를 만들기 위해 필요한 재료들을 정해놓고(Builder), 바리스타가 해당 재료들을 조합하여 커피를 만들어낼 수 있다(Director).

4-1. Product

[Coffee.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Coffee {

    private String liquid = "";

    private String beans ="";

    private String syrup = "";

    public String getLiquid() {
        return liquid;
    }

    public void setLiquid(String liquid) {
        this.liquid = liquid;
    }

    public String getBeans() {
        return beans;
    }

    public void setBeans(String beans) {
        this.beans = beans;
    }

    public String getSyrup() {
        return syrup;
    }

    public void setSyrup(String syrup) {
        this.syrup = syrup;
    }
}

4-2. Builder

[CoffeeBuilder.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class CoffeeBuilder {

    protected Coffee coffee;

    public Coffee getCoffee() {
        return coffee;
    }

    public void makeCoffee() {
        coffee = new Coffee();
    }

    public abstract void buildLiquid();

    public abstract void buildBeans();

    public abstract void buildSyrup();
}

4-3. ConcreteBuilder

[VanillaLatteBuilder.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class VanillaLatteBuilder extends CoffeeBuilder {

    @Override
    public void buildLiquid() {
        coffee.setLiquid("Milk");
    }

    @Override
    public void buildBeans() {
        coffee.setBeans("Kenya Beans");
    }

    @Override
    public void buildSyrup() {
        coffee.setSyrup("Vanilla Syrup");
    }
}

4-4. Director

[Barista.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Barista {

    private CoffeeBuilder coffeeBuilder;

    public void setCoffeeBuilder(CoffeeBuilder coffeeBuilder) {
        this.coffeeBuilder = coffeeBuilder;
    }

    public Coffee getCoffee() {
        return coffeeBuilder.getCoffee();
    }

    public void constructCoffee() {
        coffeeBuilder.makeCoffee();
        coffeeBuilder.buildLiquid();
        coffeeBuilder.buildBeans();
        coffeeBuilder.buildSyrup();
    }
}

5. 테스트

[Client.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {

    public static void main(String[] args) {
        Barista barista = new Barista();
        CoffeeBuilder vanillaLatteBuilder = new VanillaLatteBuilder();

        barista.setCoffeeBuilder(vanillaLatteBuilder);
        barista.constructCoffee();

        Coffee vanillaLatte = barista.getCoffee();
        System.out.println("액체 : " + vanillaLatte.getLiquid());
        System.out.println("원두 : " + vanillaLatte.getBeans());
        System.out.println("시럽 : " + vanillaLatte.getSyrup());
    }
}

[실행 결과]

6. 특징

  • 내부 표현을 다양하게 변화 가능 : 빌더 추상 클래스를 상속받는 새로운 빌더를 정의하여 원하는 형태의 객체를 생성 가능

  • 생성과 표현의 코드 분리 : 내부 구조를 몰라도 빌더와의 상호작용을 통해 객체 생성 가능

  • 객체 생성 절차의 세밀화 : 전달받은 객체들을 조합하여 하나의 객체를 반환하기 전까지, 내부 구성요소를 하나씩 추가하며 과정 확인 가능

Updated:

Leave a comment