빌더(Builder) 패턴

1 minute read

빌더 (Builder) 패턴이란?

빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다.

구글에 나온 설명이지만… 솔직히 나는 빌더 패턴 보면 소스에 비해 말로 하는 설명이 너무 어렵다 ;;


빌더 패턴은 많은 Optional한 멤버 변수(혹은 파라미터)나 지속성 없는 상태 값들에 대해 처리해야하는 문제들을 해결한다.

Optional 하다고 표현하는것은 개인적인 생각으로 null을 포함한다? 라는 의미인줄 알았는데

말그대로 선택적이라는것이다 ㅡ.ㅡ;;;


그렇다면 또 와이!!! 왜 빌더 패턴을 언제 쓰냐!!

예를들어, 팩토리 패턴들에서는 생성해야하는 클래스에 대한 속성 값이 많을때 다음과 같은 이슈들이 있다.

  • 클라이언트 프로그램으로부터 팩토리 클래스로 많은 파라미터를 넘겨줄 때, 타입, 순서 등에 대한 관리가 어려워져 에러가 발생할 확률이 높아진다.

  • 경우에 따라 필요없는 파라미터들에 대해서 팩토리 클래스에 일일이 null 값을 넘겨줘야 한다.

  • 생성해야 하는 sub class가 무거워지고 복잡해짐에 따라 팩토리 클래스 또한 복잡해진다.

빌더 패턴은 이러한 문제들을 해결하기 위해 별도의 Builder 클래스를 만들어 필수 값에 대해서는 생성자를 통해, 선택적인 값들에 대해서는 메소드를 통해 step-by-step으로 값을 입력받은 후에 build() 메소드를 통해 최종적으로 하나의 인스턴스를 리턴하는 방식이다.

빌더 패턴은 굉장히 자주 사용되는 생성 패턴 중 하나이고, 또한 코드에서 딱 보는순간 이거 빌더패턴이네 라고 알아볼 정도로 쉽다.


빌터 패턴의 구현 방법

  1. 빌더 클래스를 Static Nested Class(전역 중첩 클래스)로 생성한다. 위에서 말한 것처럼 코드에서 딱 보는순간 이거 빌더패턴이다 알아볼수 있다고 했는데, 그 이유가 관례적으로 생성하고자 하는 클래스 이름 뒤에 Builder를 붙이기 때문이다 .ㅋㅋ
  2. 빌더 클래스의 생성자는 public으로 하며, 필수 값들에 대해 생성자의 파라미터로 받는다.
  3. Optional한 값들에 대해서는 각각의 속성마다 메소드로 제공하며, 이때 중요한 것은 메소드의 리턴 값이 빌더 객체 자신이어야 한다.
  4. 마지막은 빌더 클래스 내에 build() 메소드를 정의하여 클라이언트 프로그램에게 최종 생성된 결과물을 제공한다. 이렇게 build() 메소드를 통해서만 객체 생성을 제공하기 때문에 생성 대상이 되는 클래스의 생성자는 private으로 정의해야 한다.

코드는 아래와 같다.

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package CreationalPattern.BuilderPattern;
 
public class Phone {
    private String ram;
    private String network;
    private boolean isIphone;
    private boolean isSamsung;
    private boolean is5G;
 
    private Phone(PhoneBuilder builder) {
        this.ram = builder.ram;
        this.network = builder.network;
        this.isIphone = builder.isIphone;
        this.isSamsung = builder.isSamsung;
        this.is5G = builder.is5G;
    }
 
    @Override
    public String toString() {
        return "Phone{" +
                "ram='" + ram + '\'' +
                ", network='" + network + '\'' +
                ", isIphone=" + isIphone +
                ", isSamsung=" + isSamsung +
                ", is5G=" + is5G +
                '}';
    }
 
    public String getRam() {
        return ram;
    }
 
    public String getNetwork() {
        return network;
    }
 
    public boolean isIphone() {
        return isIphone;
    }
 
    public boolean isSamsung() {
        return isSamsung;
    }
 
    public boolean isIs5G() {
        return is5G;
    }
 
    public static class PhoneBuilder {
        private String ram;
        private String network;
        private boolean isIphone;
        private boolean isSamsung;
        private boolean is5G;
 
        public PhoneBuilder(String ram, String network) {
            this.ram = ram;
            this.network = network;
        }
 
        public PhoneBuilder setIphone(boolean isIphone) {
            this.isIphone = isIphone;
            return this;
        }
 
        public PhoneBuilder setSamsung(boolean isSamsung) {
            this.isSamsung = isSamsung;
            return this;
        }
 
        public PhoneBuilder set5G(boolean is5G) {
            this.is5G = is5G;
            return this;
        }
 
        public Phone build() {
            return new Phone(this);
        }
    }
}
 
cs

위 코드에서 살펴봐야할 것은 Phone 클래스에는 setter 메소드가 없고 getter메소드만 가진다.

또한 생성자가 public이 아닌 private로 되있다는 것이다.

그렇기 때문에 Phone객체를 생성하기 위해서는 PhoneBuilder 클래스를 통해서만 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
package CreationalPattern.BuilderPattern;
 
public class TestPhoneBuilder {
    public static void main(String[] args) {
        Phone phone = new Phone.PhoneBuilder("16GB","skt")
                .set5G(true)
                .setIphone(false)
                .setSamsung(true)
                .build();
 
        System.out.println(phone);
    }
}
cs

위 코드를 보면 Phone 객체를 얻기 위해 PhoneBuilder 클래스를 사용하고 있으며,

필수 값 속성에 대해서는 생성자로 받고 Optional한 값들에 대해서는 메소드를 통해 선택적으로 입력 받고 있다.

Comments