본문으로 바로가기
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.



빌더 패턴에 대한 간략한 개념과 코드를 블로그에 포스팅 한 것이 있다. 그 글을 읽고 나서 아래 글을 읽는 것이 더 좋을 듯하여 링크를 남긴다.


디자인 패턴 - 빌더 패턴(Builder Pattern)


정적 팩터리나 생성자는 같은 문제를 갖고 있다. 클라스 안에 인자가 많은 상황에 잘 적응하지 못한다는 것. 아래 Person 클래스가 있다. 이런 클래스에는 어떤 생성자나 정적 팩터리 메서드가 적합할까? 보통 개발자는 아래의 예제 코드와 같이 점층적 생성자 패턴을 적용한다. 필수 인자만 받는 생성자를 하나 정의하고, 선택적 인자를 하나 받는 생성자를 추가하고, 또 추가하고 계속 추가하여 쌓아 올리는 것처럼 추가하는 것이다.


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
class Person {
    private String name; //필수
    private String age; //필수
    private String sex;
    private String phoneNumber;
    private String address;
    private String job;
    
    public Person(String name) {
        this(name, "");
    }
    
    public Person(String name, String age) {
        this(name, age, "");
    }
    
    public Person(String name, String age, String sex) {
        this(name, age, sex, "");
    }
    
    public Person(String name, String age, String sex, String phoneNumber) {
        this(name, age, sex, phoneNumber, "");
    }
    
    public Person(String name, String age, String sex, String phoneNumber, String address) {
        this(name, age, sex, phoneNumber, address, "");
    }
    
    public Person(String name, String age, String sex, String phoneNumber, String address, String job) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.phoneNumber = phoneNumber;
        this.address = address;
        this.job = job;
    }
}



하지만 문제가 있다. 필수로 들어가는 이름과 나이를 제외하고 나머지 선택 인자에는 빈 스트링("")이 들어가게 된다. 요약하자면 점층적 생성자 패턴은 잘 동작하지만 인자 수가 늘어나면 클라이언트 코드를 작성하기가 어려워지고 무엇보다 읽기 어려운 코드가 되고 만다.


생성자에 전달하는 인자 수가 많을 때 적용 가능한 두 번째 대안은 자바빈 패턴이다. 인자 없는 생성자를 호출하여 객체부터 만든 다음, 설정 메서드(Setter)을 이용하여 값을 채우는 것이다. 하지만 심각한 단점이 있다. 1회의 함수호출로 객체 생성을 끝낼 수 없으므로, 객체 일관성이 일시적으로 깨질 수 있다는 것이다. 또한 자바빈 패턴으로는 변경 불가능한 클래스를 만들 수가 없다.


다행히 점층적 생성자 패턴의 안전성에 자바빈 패턴의 가독성을 결합한 세 번째 대안이 있는데 바로 빌더(Builder) 패턴이다. 필요한 객체를 직접 생성하는 대신, 클라이언트는 먼저 필수 인자들을 생성자에 전부 전달하여 빌더 객체를 만든다. 그런 다음 빌더 객체에 정의된 설정 메서드들을 호출하여 선택적 인자들을 추가해 나간다. 그리고 마지막으로 아무 인자 없이 build 메서드를 호출하여 변겨 불가능 객체를 만드는 것이다. 빌더 클래스는 빌더가 만드는 객체 클래스의 정적 멤버 클래스로 정의한다.


아무리 떠들어봤자 예제 코드 한번 보면 다 이해가 갈 것이다. 위 링크 예제와는 조금 다르게 빌더 패턴을 구현하였으니 두개다 보는 것이 더 좋을 것 같다.


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
class Person {
    private final String name;
    private final String age;
    private final String sex;
    private final String phoneNumber;
    private final String address;
    private final String job;
    
    public static class Builder {
        private String name = "";
        private String age = "";
        private String sex = "";
        private String phoneNumber = "";
        private String address = "";
        private String job = "";
        
        public Builder(String name, String age) {
            this.name = name;
            this.age = age;
        }
        
        public Builder setSex(String sex) { this.sex = sex; return this;}
        public Builder setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; return this;}
        public Builder setAddress(String address) { this.address = address; return this;}
        public Builder setJob(String job) { this.job = job; return this;}
        
        
        public Person build() {
            return new Person(this);
        }
    }
    
    public Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.sex = builder.sex;
        this.phoneNumber = builder.phoneNumber;
        this.address = builder.address;
        this.job = builder.job;
    }
 
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", phoneNumber=" + phoneNumber + ", address=" + address + ", job=" + job + "]";
    }
}



1
2
Person person = new Person.Builder("ktko""30").setJob("Programmer").setAddress("Seoul").build();
System.out.println(person.toString()); //Person [name=ktko, age=30, sex=, phoneNumber=, address=Seoul, job=Programmer]



빌더 패턴에도 단점은 있다. 객체를 생성하려면 우선 빌더 객체를 생성해야 한다. 실무에서 빌더 객체를 만드는 오버헤드의 문제가 될 소지는 없어 보이지만, 성능이 중요한 상황에선 그렇지 않을 수도 있다. 또한 빌더 패턴은 점층적 생성자 패턴보다 많은 코드를 요구하기 때문에 인자가 충분히 많은상황에서 이용해야 한다. 인자가 적더라도, 나중에 새로운 인자를 추가해야 할 상황이 올 수 있음을 기억하자.


요약하자면 빌더 패턴은 인자가 많은 생성자나 정적 팩터리가 필요한 클래스를 설계할 때, 특히 대부분의 인자가 선택적 인자인 상황에 유용하다.


디자인 패턴에서 정리한 내용의 코드와 Effective java책을 읽고 

작성한 코드 두 개다 구현해보고 비교해보면서좀더 깊이 이해할 수 있게 되었다.

 디자인 패턴 카테고리에 있는 빌더패턴과 이 글의 내용을 같이 보는 것을 추천한다.