많은 필드와 중첩된 객체들을 단계별로 초기화해야 할 때 많은 매개 변수를 포함한 거대 생성자를 사용하면 코드가 복잡해진다. 반드시 필요하지 않은 값들도 매개 변수로 정의되므로 null을 입력해야만 하는데, 이러면 가독성이 안좋아진다.
객체 생성 코드를 추출해 빌더 클래스에 단계 별로 구성 요소를 생성하도록 해야 한다.
개념
클라이언트가 객체를 생성할 때 다양한 방법으로 생성할 수 있도록 빌더 클래스를 제공하는 패턴이다.
복합 객체 구조를 생성할 때 많이 쓰인다.
아래와 같이 Builder 인터페이스를 구현하여 다양한 생성 단계를 가진 빌더 객체를 만들 수 있다. 각 빌더 객체로부터 얻은 결과 객체는 같은 클래스 계층구조 또는 인터페이스에 속할 필요가 없다. 디렉터 클래스를 생성하면 빌더 객체로 객체를 생성하는 방법을 캡슐화할 수 있다.
아래와 같이 점층적 생성자로 인해 코드가 복잡해질 경우 빌더 패턴을 사용해 클라이언트가 필요한 단계들만 설정해 객체를 생성하도록 하면 된다.
아래에서 소개할 두 예시는 사실 완벽한 GoF 빌더 패턴은 아니다. 보통 GoF에서 제시한 것 처럼 빌더 인터페이스와 구현체를 따로 두지 않고 간편하게 정적 내부 클래스로 빌더를 정의한다.
Spring Cacheable의 빌더
빌더 클래스를 정적 내부 클래스로 선언하고, 빌더 객체를 얻기 위해 builder 정적 메서드를 제공한다.
다양한 초기화 메서드를 사용해 원하는 값들을 설정하고 build 메서드를 호출하면 생성된 객체를 얻을 수 있다.
publicstaticRedisCacheManagerBuilderbuilder(RedisCacheWriter cacheWriter) {Assert.notNull(cacheWriter,"CacheWriter must not be null");returnRedisCacheManagerBuilder.fromCacheWriter(cacheWriter);}publicstaticclassRedisCacheManagerBuilder {publicstaticRedisCacheManagerBuilderfromCacheWriter(RedisCacheWriter cacheWriter) {Assert.notNull(cacheWriter,"CacheWriter must not be null");returnnewRedisCacheManagerBuilder(cacheWriter); }// ...privatefinalMap<String,RedisCacheConfiguration> initialCaches =newLinkedHashMap<>();privateRedisCacheConfiguration defaultCacheConfiguration =RedisCacheConfiguration.defaultCacheConfig();private @NullableRedisCacheWriter cacheWriter;privateRedisCacheManagerBuilder(RedisCacheWriter cacheWriter) {this.cacheWriter= cacheWriter; }publicRedisCacheManagerBuilderallowCreateOnMissingCache(boolean allowRuntimeCacheCreation) {this.allowRuntimeCacheCreation= allowRuntimeCacheCreation;returnthis; }// ...publicRedisCacheManagerbuild() {Assert.state(cacheWriter !=null,"CacheWriter must not be null;"+" You can provide one via 'RedisCacheManagerBuilder#cacheWriter(RedisCacheWriter)'");RedisCacheWriter resolvedCacheWriter =!CacheStatisticsCollector.none().equals(this.statisticsCollector)?this.cacheWriter.withStatisticsCollector(this.statisticsCollector):this.cacheWriter;RedisCacheManager cacheManager =newRedisCacheManager(resolvedCacheWriter);cacheManager.setTransactionAware(this.enableTransactions);return cacheManager; }}
롬복의 @Builder
아래와 같이 필요한 인자를 입력받는 생성자에 @Builder 어노테이션을 붙이면 컴파일 시 롬복이 자동으로 빌더 클래스를 추가해준다.