Java BuilderPattern

Java BuilderPattern의 활용

Featured image

Effective Java의 빌더 패턴

업무를 하면서 알고리즘, 자료구조의 탄탄한 기초지식 이 정말 중요하다는 느낌을 받는다.
프로젝트를 진행 하면서 스프린트 백로그에서 개발 업무가 하나하나 지워지고
고도화 작업에 들어가면 들어갈수록 알고리즘의 비중이 점점 커지는 것 같다.
기업 공채 볼때만 필요한 줄 알았는데… 기사시험 때나…

그! 래! 서!

여러가지 패턴에 대해 공부하고 탄탄한 기본 실력을 쌓기위해 노력 해야 겠다.
실무에서 자주 마주치는 BuilderPattern에 대해 사실 Spring 환경에서는 어노테이션 으로
명시 후 아 이게 이런거구나~ 라는 것만 인지하고 좋다좋다 하며 사용을 하는데…
사실 제대로 알고써야 제대로 효율이 나올 거라 생각 한다. 아래는 Builder 패턴에 대한 자료이다.

생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.
생성자에 배개변수가 많다면 빌더를 고려하라.

깔끔한 객체 생성을 위한 패턴 3가지

  1. 점층적 생성자 패턴
  2. 점층적 생성자 패턴의 대안 자바빈 패턴
  3. 자바빈 패턴의 대안 빌더 패턴

점층적 생성자 패턴

public class Member {

	private final String name; // 필수 인자
	private final String location; // 선택적 인자
	private final String hobby; // 선택적 인자
	
	public Member(String name) {	
		this(name, "출신지역 비공개", "취미 비공개");
	}
	
	public Member(String name, String location) {
		this(name, location, "취미 비공개");
	}

	public Member(String name, String location, String hobby) {
		this.name = name;
		this.location = location;
		this.hobby = hobby;
	}
}
// 호출 코드만으로는 각 인자의 의미를 알기 어렵다.
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 3, 35, 27);
NutritionFacts pepsiCola = new NutritionFacts(220, 10, 110, 4, 30);
NutritionFacts mountainDew = new NutritionFacts(230, 10);

자바빈 패턴

따라서 이에 대한 대안으로 자바빈 패턴(JavaBeans Pattern)을 소개한다.
이 패턴은 setter메서드를 이용해 생성 코드를 읽기 좋게 만드는 것이다.

NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohdydrate(27);

빌더 패턴(Effcetive Java 스타일)

//Effective Java의 Builder Pattern
public class NutririonFacts {
	private final int servingSize;
	private final int servings;
	private final int calories;
	private final int fat;
	private final int sodium;
	private final int carbohydrate;
	
	public static class Builder {
		// Required parameters(필수 인자)
		private final int servingSize;
		private final int servings;
		
		// Optional parameters - initialized to default values(선택적 인자는 기본값으로 초기화)
		private int calories	  = 0;
		private int fat			  = 0;
		private int carbohydrate  = 0;
		private int sodium 	      = 0;
		
		public Builder(int servingSize, int servings) {
			this.servingSize = servingSize;
			this.servings	 = servings;
		}
		
		public Builder calories(int val) {
			calories = val;
			return this; // 이렇게 하면 . 으로 체인을 이어갈 수 있다.
		}
		
		public Builder fat(int val) {
			fat = val;
			return this;
		}
		
		public Builder carbohydrate(int val) {
			carbohydrate = val;
			return this;
		}
		
		public Builder sodium(int val) {
			sodium = val;
			return this;
		}
		
		public NutririonFacts build() {
			return new NutririonFacts(this);
		}
	}
	
	private NutririonFacts(Builder builder) {
		servingSize	 = builder.servingSize;
		servings	 = builder.servings;
		calories	 = builder.calories;
		fat			 = builder.fat;
		sodium		 = builder.sodium;
		carbohydrate = builder.carbohydrate;
	}
}

위와 같이 하면 다음과 같이 객체를 생성할 수 있다.

NutritionFacts.Builder builder = new NutritionFacts.Builder(240, 8);
builder.calories(100);
builder.sodium(35);
builder.carbohydrate(27);
NutritionFacts cocaCola = builder.build();

또는 다음과 같이 사용할 수도 있다.

// 각 줄마다 builder를 타이핑하지 않아도 되어 편리하다.
NutritionFacts cocaCola = new NutritionFacts
    .Builder(240, 8)    // 필수값 입력
    .calories(100)
    .sodium(35)
    .carbohydrate(27)
    .build();           // build() 가 객체를 생성해 돌려준다.

장점

객체 생성을 유연하게

빌더 패턴을 사용하면 하나의 빌더 객체로 여러 객체를 만드는 것도 가능하다.

인자가 설정된 빌더는 훌륭한 추상적 팩토리다.

위의 인용구는 이펙티브 자바의 저자인 조슈아 블로흐가 GoF 책의 빌더 패턴 부분을 인용한 것이다.

public interface Builder<T> {
    public T build();
}

위와 같은 인터페이스를 만들고, 빌더 클래스가 implements 하게 하면 된다.