디자인 패턴

[디자인 패턴] 빌더 패턴(Builder Pattern)

우디혜 2020. 11. 14. 20:43

Creational Design Pattern 중 하나이다.

 

Head First Design Pattern의 예시를 통해 살펴보면

 

Vacation 인스턴스를 만드는데

client 1은 호텔, 점심, 렌트카

client 2는 호텔

client 3는 호텔, 저녁, 렌트카, 전망대

를 요청했다고 가정하면

 

Vacation 클래스는 client 모두의 요청을 포괄해야하기 때문에 각 client들의 요청을 인스턴스화하기 위해서는

client 1을 위한 Vacation(호텔 h, 점심 l, 렌트카 c)

client 2을 위한 Vacation(호텔 h)

client 3을 위한 Vacation(호텔 h, 저녁 d, 렌트카 c, 전망대 v)

 

이렇게 3개의 다른 생성자를 만들어주거나, 모든 변수를 포괄하는 생성자 하나를 만들어 빈 곳은 null 값을 넣어주어야한다. 물론, 두 가지 상황 다 별로다. 변수의 개수가 늘어나면 더욱 더 못생긴 코드가 완성될 것이다..! 심지어 타입 순서가 모두 정확하게 맞아야하기 때문에 유연한 구조도 아니다.

 

그래서 이런 문제를 해결하기 위해 나온 것이 Builder Pattern이다.

 

필수적인 요소들만 생성자를 통해 넣어주고,

나머지 선택적인 값들은 메소드를 통해 따로 값을 넣어준다

그리고나서 build() 메소드로 최종적으로 만들어진 인스턴스를 리턴한다!

 

Builder 패턴을 다시 공부하기 위해 이 글을 찾은 나는 바보같이 또 모를 수도 있기 때문에 예시를 들겠다.

 

public class User {

    private final Long seq;

    private final String email;

    private String passwd;

    private Integer loginCount;
    
    // getter method only
 }

 [ User Class, Attributes, and Getter ]

위와 같은 User 클래스가 있다고 가정한다.

여기서 getter 메소드만 존재하는 이유는 User 객체 자체는 직접적인 수정에 대해 닫혀있어야하기 때문이다. setter로 수정이 가능하게끔 만들면 ㄴㄴ.

 

private User(String email, String passwd) {
        this.email = email;
        this.passwd = passwd;
}
private User(UserBuilder builder) {
        this.seq = builder.seq;
        this.email = builder.email;
        this.passwd = builder.passwd;
        this.loginCount = builder.loginCount;
    }

[ Constructor ]

계정 생성에 꼬옥 필요한 email과 passwd는 constructor의 변수로 넣어준다. 그리고 User 클래스 자체는 보호되어야하므로 private 처리를 해준다.

이후 생성된 builder를 통해서 User 인스턴스가 만들어질 수 있게끔, UserBuilder를 파라미터로 받는 constructor도 만들어준다.

 

static public class UserBuilder{

        private Long seq;
        private String email;
        private String passwd;
        private Integer loginCount;
        
    public UserBuilder seq(Long seq){
         this.seq = seq;
         return this;
    }
    public UserBuilder email(String email){
         this.email = new Email(email);
         return this;
    }
    public UserBuilder passwd(String passwd){
         this.passwd = passwd;
         return this;
    }
    public UserBuilder loginCount(Integer loginCount){
         this.loginCount = loginCount;
         return this;
    }
    
    public UserBuilder build(){
    	return new User(this);
    }
 }

[ UserBuilder Class ]

그리고 builder 패턴을 적용하여 만들어진 UserBuilder 클래스!

난 이 클래스를 User 클래스 안에 static으로 존재하게끔 했다.아예 builder 클래스를 분리하는 경우도.. 있는 것같더라 그 방법은 다음에 찾아봐야겠당

 

 

그럼 이제 User 객체를 만들어 보자!

new User.Builder(email, passwd).build()
// 회원가입을 위한 기본정보
new User.Builder(email, passwd).loginCount(2).build()
// 회원가입 기본정보 + login 횟수
new User.Builder(email, passwd).seq(1111).loginCount(3).build()
// 회원가입 기본정보 + seq 정보 + login 횟수

 

Builder 패턴을 적용하여 이제는 각각 다른 객체 요청에 대응할 수 있는 상태가 되었다!!

 

 

빌더 패턴의 특징은,

  1. 객체화 '과정'을 캡슐화한다.

    • 객체를 얻기 위해서는 반드시 builder 클래스를 통해서만 가능하다

    • 객체의 내부를 클라이언트로부터 보호할 수 있다.
  2. 객체를 단계별로 생성할 수 있다. 그렇기 때문에 조금 더 유연하게 다양하게 객체 생성이 가능하다.

    • 팩토리 패턴과의 차이가 여기서 이루어진다. 팩토리 패턴은 어쨌든 한 번 정의된 순서가 있으면 그 순서대로 이루어지지만 빌더 패턴은 이에 대해 유연한 대처가 가능하다. 따라서 정형화 되어있는 클래스에는 팩토리 패턴을, 변동성이 높은 클래스에는 빌더 패턴을 사용하면 될 듯하다

 

 

 

'디자인 패턴' 카테고리의 다른 글

[디자인 패턴] SOLID 원칙  (0) 2020.11.20