본문 바로가기
프로그래밍/자바

[effective java2]규칙2. 생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.

by 카라미 2017. 9. 7.

객체의 생성과 삭제

규칙2. 생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.

정적팩터리나 생성자는 선택적 인자가 많은 상황에 잘 적응하지 못한다는 같은 문제를 갖고 있다.
- 생성자 인자가 많아지면 첫번째 대안!! 점층적 생성자 패턴
public class NutritionFacts {
	private final int servingSize; // (mL) required
	private final int servings; // (per container) required
	private final int calories; // optional
	private final int fat; // (g) optional
	private final int sodium; // (mg) optional
	private final int carbohydrate; // (g) optional

	public NutritionFacts(int servingSize, int servings) {
		this(servingSize, servings, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories) {
		this(servingSize, servings, calories, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories, int fat) {
		this(servingSize, servings, calories, fat, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories, int fat,
			int sodium) {
		this(servingSize, servings, calories, fat, sodium, 0);
	}

	public NutritionFacts(int servingSize, int servings, int calories, int fat,
			int sodium, int carbohydrate) {
		this.servingSize = servingSize;
		this.servings = servings;
		this.calories = calories;
		this.fat = fat;
		this.sodium = sodium;
		this.carbohydrate = carbohydrate;
	}

	public static void main(String[] args) {
		NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
	}
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
인자에 들어있는 값들이 무엇을 의미하는지 알기 어렵다.. 인자가 이것보다 더~~~ 많다면??? 더 힘들어질 것이다. 
 - 이런 점층적 생성자 패턴은 잘 동작하지만, 인자 수가 늘어나면 클라이언트 코드를 작성하기가 어려워지고, 무엇보다 읽기 어려운 코드가 된다. 

두번째 대안!! 자바빈 패턴 -인자없는 생성자를 호출하여 객체를 만든 다음, setter 메소드를 호출하여 필수필드뿐 아니라 선택적 필드의 값들을 채운다.
public class NutritionFacts {
	// Parameters initialized to default values (if any)
	private int servingSize = -1; // Required; no default value
	private int servings = -1; // "     " "      "
	private int calories = 0;
	private int fat = 0;
	private int sodium = 0;
	private int carbohydrate = 0;

	public NutritionFacts() {
	}

	// Setters
	public void setServingSize(int val) {
		servingSize = val;
	}

	public void setServings(int val) {
		servings = val;
	}

	public void setCalories(int val) {
		calories = val;
	}

	public void setFat(int val) {
		fat = val;
	}

	public void setSodium(int val) {
		sodium = val;
	}

	public void setCarbohydrate(int val) {
		carbohydrate = val;
	}

	public static void main(String[] args) {
		NutritionFacts cocaCola = new NutritionFacts();
		cocaCola.setServingSize(240);
		cocaCola.setServings(8);
		cocaCola.setCalories(100);
		cocaCola.setSodium(35);
		cocaCola.setCarbohydrate(27);
	}
- 작성해야하는 코드의 양이 조금 많아지긴 해지만, 읽기도 생성하기도 쉽다. 그러나!!! 1회의 함수 호출로 객체 생성을 끝낼 수 없으므로, 객체 일관성이 일시적으로 깨질수 있다. 또한 변경 불가능 클래스를 만들 수 없다. 


세번째 대안!!! 빌더패턴
1. 필요한 객체를 직접 생성하는 대신, 클라이언트 는 먼저 필수 인자들을 생성자(또는 정적 팩터리 메소드)에 전부 전달하여 빌더객체를 만든다.
2. 빌더 객체에 정의된 설정 메서드들을 호출하여 선택적 인자들을 추가
3. 아무런 인자 없이 build메서드를 호출하여 변경 불가능 객체를 만든다. 
 (빌더 클래스는 빌더가 만드는 객체 클래스의 정적 멤버 클래스로 정의한다)
public class NutritionFacts {
	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 NutritionFacts build() {
			return new NutritionFacts(this);
		}
	}

	private NutritionFacts(Builder builder) {
		servingSize = builder.servingSize;
		servings = builder.servings;
		calories = builder.calories;
		fat = builder.fat;
		sodium = builder.sodium;
		carbohydrate = builder.carbohydrate;
	}

	public static void main(String[] args) {
		NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
				.calories(100).sodium(35).carbohydrate(27).build();
	}
빌더패턴의 단점!! 객체를 생성하려면 우선 빌더를 생성해야한다. 빌더패턴은 점층적 생성자 패턴보다 많은 코드를 요구한다. 따라서 인자가 충분히 많은 상황에서 이용.. 지금은 작아도 나중에 추가될 수 있음을 기억!!! 


  요약 빌더패턴은 인자가 많은 생성자나 정적 팩터리가 필요한 클래스를 설계할 때, 특히 대부분의 인자가 선택적 인자인 상황에 유용하다.



'프로그래밍 > 자바' 카테고리의 다른 글

[effective java2]규칙1. 생성자 대신 정적 팩터리 메소드를 사용할 수 없는지 생각해 보라  (0) 2017.09.06
Exception 예제  (0) 2016.02.23
ChatClient  (0) 2016.01.22
EchoThreadServer  (0) 2016.01.22
Echo  (0) 2016.01.22