우리네 장

[ GoF ] 구현을 통해 빌더 패턴 익히기 본문

아키텍쳐

[ GoF ] 구현을 통해 빌더 패턴 익히기

qpmi1zm29 2022. 7. 15. 17:29

빌더 패턴은 생성자 패턴 중 하나로써, 인스턴스를 생성하는 방법을 정의한다. 

 

위와 같이 TourPlan 이라는 클래스가 존재 할 때

해당 인스턴스를 생성 할 때 모든 속성 값이 초기화 되어야 하는 경우가 있고,

불필요 하여 임의의 속성들만 값이 초기화 되어야 하는 경우가 있다. 

 

 

이를 생성자로 구현하게 되면,

초기화 할 변수에 따라서 여러 개의 생성자가 생길되어 코드가 복잡해 질 수 있다.

혹은 전체 파라미터를 세팅하는 생성자 하나만을 가지고 사용할 수 있으나

파라미터를 넘겨줄 때 코드 상에서 NULL 값을 사용하게 된다는 단점이 있다. 

 

이럴 때 빌더 패턴을 적용하게 되는데,

위와 같이 불필요한 생성자를 만들지 않아도 될 뿐만 아니라 

특정 타입의 인스턴스를 생성하는 생성 프로세스를 정의할 수 있다는데 의미가 있다. 

 

그 뿐만 아니라, 인스턴스 생성 시 특정 조건을 강제해서 값을 세팅할 수도 있으며,

인스턴스의 속성 값 세팅 시 초기화 순서를 강제할 수도 있다.

그리고 생성한 인스턴스를 클라이언트 코드에 반환해 주기 전에 한 번 더 완전성을 검증할 수도 있다. 

 

 

대략적인 빌더 패턴 구조

 

다양한 타입의 빌더와 Product 인스턴스를 생성할 것이 아니라면, 

굳이 인터페이스는 사용할 필요는 없다. 

 

빌더 패턴에서 필수적으로 사용되는 요소는 builder 클래스와 해당 빌더로 생성되는 product 클래스 이다. 

 

director는 빌더 패턴의 보조 수단으로 사용되는데,

특정 속성 값을 가진 product 인스턴스의 생성이 반복적으로 이루어지는 경우에,

해당 인스턴스의 생성 프로세스를 director 클래스에 함수로 만들고

client에서는 해당 함수만 호출하여 인스턴스를 생성하도록 한다.

 

이는 인스턴스의 생성 과정을 숨겨주기 때문에 캡슐화의 일종으로 볼 수 있다.

 

아래 예시에는 director에 대한 내용은 제외하고 구현하였다. 

위에서 언급했던 장점들을 코드에서 어떻게 구현이 가능한지 살펴보자.

 

 

TourPlan.java

product class

 

product 클래스로 기본 생성자와 속성들에 대한 getter, setter로만 이루어져 있다.

단순하게 구현하고자 인터페이스 들은 정의하지 않았다.

 

TourPlanBuilder.java

 

builder class

TourPlan 클래스의 인스턴스를 생성해주는 TourPlanBuilder 클래스이다. 

 

여기서 중요한 점은,

빌더 클래스는 상태 값을 갖는다는 점이다. 

여기서는 private TourPlan tourPlan; 이 상태 값에 해당한다.

이는 멀티 스레드 환경에서 불안전한 요소이기 때문에, 스레드마다 빌더 클래스의 인스턴스를 생성해서 사용하는 것이

일반적이다. ( 아래 client 코드 참고 )

 

빌더 클래스가 세팅해 주는 속성이 많은 경우 저렇게 VO 자체를 속성으로 갖기도 한다.

 

위 빌더를 구현하면서 신경쓴 부분은 두 가지 이다.

1. 여행 계획의 시작날짜와 종료날짜는 반드시 둘 다 정의가 되어야 한다. 

     하나만 정의되는 경우는 없다. ( 제약 조건에 해당 )

 

 

 

product 클래스에는 setStartDate와 setEndDate가 별개로 선언이 되어 있으나,

빌더에서 명명을 And로 엮어주었고, 메소드 선언부터 두 개의 파라미터를 받도록 정의 하였다. 

 

이를 이용해서 기간에 대한 값을 세팅해줄 때 시작 날짜와 종료 날짜를 모두 세팅해주도록 강제 해줄 수 있다. 

 

 

2. 여행 계획에서 장소와 기간을 먼저 정의하고, 여행 계획의 이름, 비용, 수용 가능 인원은 뒤에 정의하도록 한다.

     ( 순서 강제성 )

 

 

빌더 패턴은 client 코드에서 인스턴스 생성 시 메소드 체이닝을 사용하기 때문에 

각 속성을 세팅하는 메소드의 return 타입이 builder 가 된다. 

 

속성 순서를 강제하기 위해,

먼저 세팅이 필요한 여행 장소, 기간에 대한 빌더 ( TourPlanBuilder )

후에 세팅이 필요한 계획 명, 금액, 수용 가능 인원에 대한 빌더 ( TourPlanBuilderF ) 를 따로 정의해 주었다. 

 

그러나 빌더는 상태 값을 갖기 때문에

별개의 두 빌더가 하나의 상태 값에 접근이 가능해야 한다는 문제가 있었다.

 

그래서 후에 세팅을 지원해주는 TourPlanBuilderF를 inner class에 정의하여, outer class에 접근이 가능하도록 정의하였다. 

 

App.java ( client 코드 )

 

client code

실제 빌더를 사용하는 클라이언트 코드를 보면,

메소드 체이닝 방식을 사용해 tourPlan 이라는 인스턴스의 속성 값들을 세팅해주고 있다. 

 

getInstance() 메소드에서 

TourPlanBuilder 의 private TourPlan tourPlan; 변수를 초기화 해주면서 + TourPlanBuilder 인스턴스를 return 해준다.

 

TourPlanBuilder 인스턴스를 return 해줌으로써 장소, 기간 외 속성들을 세팅해주는 메소드를 찾을 수 없어

두 속성들을 우선적으로 설정하게 된다. 

 

 

프로세스 마지막에서 build() 를 호출하면 product 클래스 타입의 인스턴스를 return 해준다. 

 

 

 

'아키텍쳐' 카테고리의 다른 글

Facade 디자인 패턴  (0) 2023.12.30
싱글톤 패턴  (0) 2023.12.27