티스토리 뷰

공부자료

[디자인패턴] 빌더패턴 / Builder Pattern

임다솜 임다솜 2016.12.03 12:48

2016. 12. 03 주말스터디 


다이어그램




학습내용

@빌더 패턴이란 무엇일까?

@생각해볼 것 : 생성에 대한 책임을 꼭 그 오브젝트가 가져야 할까?

@(libstreaming의 Session을 예로 들면, Session의 생성자가 public이면 빌더를 사용할 필요가 없다.)

Product의 생성자의 접근제어자가 중요하다!


@생각해볼것 2: 객체에 들어가는 멤버변수의 유효성에 대한 책임을 누가 가지는 것이 좋을까?

객체 자신이 가지는 것이 좋을 수도 잇고, 빌더는 웬만하면 빌더만 하면 좋겠다.

하지만 답은 없고 가장 최선의 방향으로 해야겟지.


@빌더안에 객체 생성의 책임을 주고, 클라이언트는 객체를 잘못생성하는 등에 오류를 줄이고 부담을 줄여줄 수 있다.

(ex: Spring의 MessageBuilder()에서 메세지의 내용에 따라 GenericMessage, ErrorMessage를 return하는데 이렇게 두개의 오브젝트를 생성하는 것이 과연 한 Object 클래스에서 하는 것이 맞을까? 하는 문제가 있다.)


@인자내용이 많아야만 빌더패턴을 쓰는가??

아닌 것 같다.


@언제 빌더 패턴을 써야할까?

생성 로직이 복잡할때, 생성에 넘어가는 파라미터가 많을 때, 객체를 생성하기 위해 다른 것들을 체크하거나, 다른 객체를 생성하는 등의 복잡한 일이 있을 때!


실제 코드에 있는 내용 분석해보기


StringBuilder

append() -->setter() 와같은역할!

toString() --> build()와 같은 역할!


유효성검사는 어디서? super.append()에서!

String이나 StringBuilder 모두 유효성 검사를 하고 있다


Guava에서 GraphBuilder

정적 메서드로 빌더를 만든다.

ConfigurableMutableGraph의 생성자에서 ValueGraph를 생성하면서 빌더를 넘겨서 ValueGraph의 속성을 셋팅한다. 그리고 그걸 backingValueGraph로 받아서 얘를 호출한다.

실제 빌더가 생성되는 건 ValueGraph

ConfigureableMutableGraph.java에서 ValueGraph.java를 생성해서 ValueGraph의 메서드를 호출하는데

감쌋다.


Spring의 BeanDefinitionBuilder

스프링에서 Bean을 관리하는데 필요한 메타정보를 가지고 있는 것이 BeanDefinition이다.

이 BeanDefinition을 생성하는 Builder가 BeanDifinitaionBuilder!


rootBeanDefinition()으로 빌더인스턴스 가져오고, addXXX()로 세팅하고, getBeanDefinition()으로 build()한다.


-BeanDefinitionBuilder는 생성자가 private이다. 그래서 static method를 통해서만 Builder객체를 생성할 수 있도록 되어 있다

-Builder 객체를 생성할 때에는 static method를 통해서만 생성할 수 있다. 그리고 또 다른 점이 이 Builder를 생성함과 동시에 BeanDefinition을 같이 생성한다. (다른 방식에서는 build()를 호출할 때 Product를 생성했는데, 얘는 Builder생성과 함께 Product를 생성하는 방식인 것이다)

-build()와 같은 역할을 하는 getBeanDefinition() 코드를 보면 this.beanDefinition.validate()라는 것을 호출한다. 즉, Bean자체에서 유효성검사를 하는 것.


elasticSearch의 CacheBuilder ★Clean code!

IndicsRequestCache.java에서 CacheBuilder를 이용해서 빌더와 캐시(Product)를 생성한다.

BitsetFilterCache.java에서도 CacheBuilder를 이용해서 빌더와 캐시를 생성한다.


-CacheBuilder.java는 구성이 심플하다. 

-이 CacheBuilder도 생성자가 private이다. static method(build())를 통해서만 빌더객체를 생성할 수 있다.

-얘는 이 빌더객체의 Setter에서 유효성검사를 한다.

-그리고 build()가 호출되면 이 안에서도 유효성 검사를 한다. 근데 여기서 또 유효셩검사를 외ㅐ할까?


String의 MessageBuilder ★Clean code!

MessageBuilder는 set, build의 과정없이 createMessage() 하나만으로 바로 생성한다.

얘가 특이한 건 createMessage()라는 Factory Method와 build()라는 메서드 두개가 있따. 둘 다 객체 생성한다. 근데 뭐가 다른걸까 생각해보면, createMessage(...)는 메세지를 넣어서 바로 생성해서 간편하게 만들수있고, build(...)는 set, set해서 파라미터를 충분히 설정을 해주고 build()로 생성하게 된다. 


기타 알게 된 것

@ 알게 된 것 1

if( ddd == null){ ... } 이렇게 쓸 필요없다.

그럼 not null 체크는 어떻게 하는 것이 좋을까요?

스프링 --> Assert.notNull(...) 을 사용하는 것이 좋다! 

자바 --> Objects.requireNonNull(...)


@ 알게 된 것 2

public > protected > package private > private

package private은 뭘까? 패키지에 private한 것! 다른 패키지에서 접근 못한다!

--> 그래서 Cache, CacheBuilder가 같은 패키지이고 Cache가 package private(default)이므로 Cache는 외부(특히, API를 사용하는 사용자)에서 생성할 수 없고 무조건 Builder를 통해서만 생성이 가능하도록 했다. CacheBuilder는 Cache와 같은 패키지에 있으므로 Cache가 private이어도 접근 가능.


댓글
댓글쓰기 폼
공지사항
Total
41,170
Today
70
Yesterday
59
링크
TAG
more
«   2018/07   »
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        
글 보관함