Builder Pattern


빌더 패턴(Builder Pattern)은 복잡한 객체의 생성 과정과 표현 방법을 분리하여 다양한 구성의 인스턴스를 만드는 생성 패턴이다. 생성자에 들어갈 매개 변수를 메서드로 하나하나 받아들이고 마지막에 통합 빌드하여 객체를 생성하는 방식이다.

빌더 패턴 생성까지


점층적 생성자 패턴

점층적 생성자 패턴은 필수 매개변수와 함께 선택 매개변수를 0개, 1개, 2개 등등으로 받는 형태로, 다양한 매개변수를 입력받아 인스턴스를 생성하고 싶을 때 사용하던 생성자를 오버로딩하는 방식이다.

	public subway(int bread, int pickle, int bacon, int cabbage, int tomato){
    	this.bread = bread;
        this.pickle = pickle;
        this.bacon = bacon;
        this.cabbage = cabbage;
        this.tomato = tomato;
    }
     
    public subway(int bread, int bacon, int tomato){
    	this.bread = bread;
        this.bacon = bacon;
        this.tomato = tomato;
    }

점층적 생성자 패턴의 경우 인스턴스 필드들이 많을수록 생성자에 들어갈 인자의 수가 늘어나 개발자가 헷갈리게 된다. 이러한 방법은 생성자 메서드 수가 너무 많이 늘어나 가독성 혹은 유지보수 측면에서 좋지 않다.

자바 빈 패턴

자바 빈 패턴은 Setter 메소드를 이용한 방법이다. 매개변수가 없는 생성자로 객체 생성 후 Setter 메소드를 이용해 클래스의 초깃값을 설정하는 방식이다.

class Subway {
	//필수
    private int bread;
    private int bacon;
    
    //부가
    private int tomato;
    private int pickle;
    private int cabbage;
    
    public Subway(){}
    
    public void setBread(int bread){
    	this.bread = bread;
    }
    public void setBacon(int bacon){
    	this.bacon = bacon;
    }
    public void setTomato(int tomato){
    	this.tomato = tomato;
    }
    public void setPickle(int pickle){
    	this.pickle = pickle;
    }
    public void cabbage(int cabbage){
    	this.cabbage = cabbage;
    }
    
}

기존 생성자 오버로딩에서 발생했던 가독성 문제 해결, 선택적 파라미터에 대해 해당 되는 Setter 메서드만 호출하여 유연적으로 객체가 생성이 가능해졌다.

하지만 자바 빈 패턴은 객체 생성 시점에 모든 값을 주입하지 않기 때문에 다음과 같은 2가지 문제가 발생한다.

1.일관성문제
매개변수에는 객체가 초기화될 때 반드시 설정되어야 하는 값인 필수 매개변수와 객체 초기화 시 선택적으로 설정되면 되는 선택적 매개변수가 있는데, 개발자가 깜빡하고 필수 매개변수를 호출하지 않으면 객체는 일관성이 무너지게 된다. 이렇게 생성된 객체는 유효하지 않으며 다른 곳에서 해당 인스턴스 사용시 에러를 유발할 수 있다.

2.불변성문제
객체를 생성했음에도 여전히 외부적으로 Setter 메소드를 노출하기 때문에 협업 과정에서 누군가 Setter 메서드를 호출하여 함부로 객체를 조작할 수 있다. 이러한 점은 객체의 불변함으로 보장할 수 없게 한다.

빌더 패턴


위의 단점들을 보완하여 빌더 패턴은 필요한 인스턴스 필드들을 한줄씩 받고 그 후 최종적으로 build() 메소드를 통해 하나의 인스턴스를 생성하여 리턴한다.
이때, 다른 방식으로 샌드위치를 만드는 여러 다른 빌더 클래스를 생성할 수 있으며 이 클래스들을 통해 다양한 종류의 객체를 생성할 수 있다.

구조

  1. 빌더 : 빌더 인터페이스는 모든 유형의 빌더들에 공통적인 제품 생성 단계들을 선언한다.
  2. 구상 빌더 : 구성 빌더들은 생성 단계들의 다양한 구현을 제공한다. 이 구상 빌더들은 공통 인터페이스를 따르지 않는 제품들도 생산할 수 있다.
  3. 제품들 : 제품들은 그 빌더를 통해 나온 객체들이다.
  4. 디렉터 : 디렉터 클래스는 생성 단계들을 호출하는 순서를 정의하므로 제품들의 특정 설정을 만들고 재설정할 수 있다.
  5. 클라이언트 : 빌더 객체들 중 하나를 디렉터와 연결해야한다. 일반적으로 위 연결은 디렉터 생성자의 매개변수들을 통해 한번만 수행되며, 그 후 디렉터는 모든 추가 생성에 해당 빌더 객체들을 사용한다. 하지만 클라이언트가 빌더 객체를 디렉터의 production 메서드에 전달할 때를 위한 대안적 접근 방식이 있으며, 이 때 디렉터와 함께 무언가를 만들 때마다 다른 빌더를 사용할 수 있다.

장점

1. 객체 생성 과정을 일관된 프로세스로 표현한다.
2. 디폴트 매개변수 생략을 간접적으로 지원한다.

  • 디폴트 매개변수가 설정된 필드를 설정하는 메서드를 호출하지 않는 방식으로 디폴트 매개변수를 생략하고 호출하는 효과를 간접적으로 구현할 수 있다.

3. 필수 멤버와 선택적 멤버를 분리 가능하다.

  • 초기화과 필수인 멤버는 빌더의 생성자로 받게 하여 필수 멤버를 설정해주어야 빌더 객체가 생성되도록 유도하여 사용자로 하여금 필수 멤버와 선택 멤버를 구분하여 객체 생성을 유도할 수 있다.

4. 객체 생성 단계를 지연할 수 있다.

  • 빌더를 재사용함으로써 객체 생성을 주도적으로 지연할 수 있다.

5. 초기화 검증을 멤버별로 분리할 수 있다.
6. 멤버에 대한 변경 가능성 최소화를 추구할 수 있다.

  • 위에서 말한 것처럼 자바 빈 패턴의 불변성의 문제점을 보완하였다.

단점

1. 코드 복잡성이 증가한다
2. 생성자보다 성능이 떨어진다.
3. 지나친 빌더의 남용은 금지해야한다

빌더 패턴의 종류

  1. 심플 빌더 패턴(Effective Java) : 생성시 지정해야 할 인자가 많을 때 사용하며 객체의 일관성 불변성을 목적으로 한다.
  2. GoF의 빌더 패턴 : 객체의 생성 단계 순서를 결정해두고 각 단계를 다양하게 구현하고 싶을 때 사용한다.

참고


profile
안녕안녕안녕

0개의 댓글