규칙 2. 생성자에 매개변수가 많다면 빌더를 고려하라
이 장에서는 선택적 인자가 많을 때 객체 생성하는 방법들의 특징을 살펴보고, 왜 빌더Builder 를 고려해야하는지 얘기한다.
- 
점층적 생성자 패턴telescoping constructor pattern 
- 
자바빈즈 패턴JavaBeans pattern 
- 
빌더 패턴Builder pattern 
점층적 생성자 패턴
기본적으로 필수 인자만 받는 생성자를 정의하고, 선택적 인자를 받는 생성자를 추가하는 방법이다. 객체를 생성할 때 인자 갯수에 맞는 생성자를 골라 호출해야한다.
public class Person {
	private final String name; // 필수
	private final int age; // 필수
	private final String mail;
	private final String city;
	private final String state;
	public Person(String name, int age) {
		this(name, age, "");
	}
	public Person(String name, int age, String mail) {
		this(name, age, mail, "");
	}
	public Person(String name, int age, String mail, String city) {
		this(name, age, mail, city, "");
	}
	public Person(String name, int age, String mail, String city, String state) {
		this.name = name;
		this.age = age;
		this.mail = mail;
		this.city = city;
		this.state = state;
	}
}- 
설정할 필요가 없는 필드에도 인자를 전달해야 해야 한다. 
- 
인자 수가 늘어날수록 가독성이 떨어진다. 
자바빈즈 패턴
인자 없는 생성자로 객체를 할당받고, setter를 통해 나머지 값들을 설정하는 방법이다. 객체 생성도 쉽고 위 방법보다 가독성이 좋다.
public class Person {
    private String name;
    private int age;
    private String mail;
    private String city;
    private String state;
    public Person() {}
    public void setName(String name) { this.name = name; }
    public void setAge(int age) { this.age = age; }
    ....
}Person me = new Person();
me.setName("yeongjun.kim");
me.setAge(27);- 
한번에 객체 생성을 끝낼 수 없으므로, 객체 일관성이 일시작으로 깨질 수 있다. 
- 
변경 불가능 클래스를 만들 수 없다. 해결하기 위해서 추가 구현할 코드가 많아진다. 
- 
setter를 추가로 만들어줘야한다. (내생각) Tipsetter 생성방법보통 IDEA에 getter/setter를 자동으로 추가해주는 기능이 존재한다. 혹은 lombok의 @Setter어노테이션을 활용할 수 있다.
빌더 패턴
필수 인자들을 생성자(또는 정적 팩터리 메서드)에 전달하여 빌더 객체를 만들고, 선택적 인자들을 추가한 뒤, 마지막에 build() 를 호출하여 Immutable 객체를 만드는 방법이다.
public class Person {
	private final String name;
	private final int age;
	private final String mail;
	private final String city;
	private final String state;
	// 빌더 객체
	public static class Builder {
		// 필수 인자
		private final String name;
		private final String age;
		// 선택적 인자 - 기본값으로 초기화
		private final String mail = "";
		private final String city = "";
		private final String state = "";
		public Builder(String of, int age) {
			this.name = name;
			this.age = age;
		}
		public Builder mail(String mail) {
			this.mail = mail;
			return this;
		}
		public Builder city(String city) {
			this.city = city;
			return this;
		}
		public Builder state(String state) {
			this.state = state;
			return this;
		}
		public Person build() {
			return new Person(this);
		}
	}
	private Person(Builder builder) {
		this.name = name;
		this.age = age;
		this.mail = mail;
		this.city = city;
		this.state = state;
	}
}Person me = Person.Builder("yeongjun.kim", 27)
	.mail("opid911@gmail.com")
	.build();특징
- 
빌더 클래스(Builder)는 빌더가 만드는 객체 클래스(Person)의 정적 맴버 클래스로 정의한다({#item22}[규칙 22]). public class Person { public static class Builder { ... } }
- 
불변식을 적용할 수 있으며, build()에서 불변식이 위반되었는지 검사할 수 있다.public class Person { public static class Builder { ... public Person build() { Person result = new Person(this); if(/* result의 값 검사 */) { throw new IllegalStateException(/* 위반 원인 */); } return result; } } }
- 
빌더 객체에서 실제 객체로 인자가 복사된 다음에 불변식들을 검사할 수 있다는 것, 그리고 그 불변식을 빌더 객체의 필드가 아니라 실제 객체의 필드를 두고 검사할 수 있다는 것은 중요하다({#item39}[규칙 39]). 
- 
불변식을 위반한 경우, build()는IllegalStateException을 던져야 한다({#item60}[규칙 60]).
- 
예외 객체를 살펴보면 어떤 불변식을 위반했는지 알아낼 수도 있어야 한다({#item63}[규칙 63]). 
cf. 불변식을 강제하는 방법
- 
불변식이 적용될 값 전부를 인자로 받는 setter를 정의하는 방법. 
- 
setter는 불변식이 만족하지 않으면 *IllegalArgumentException*을 던짐. 
- 
build()가 호출되기 전에 불변식을 깨뜨리는 인자가 전달되었다는 것을 신속하게 알 수 있는 장점. 
public class Person {
	...
	public static class Builder {
		public Builder setNameAndAge(String name, int ate) {
			if(name == null) {
				throw new IllegalArgumentException();
			}
			return this;
		}
		...
		public Person build() {
			return new Person(this);
		}
	}
	...
}- 
메서드마다 하나씩, 필요한 만큼 varargs 인자를 받을 수 있다. 
	public class Person {
		public static class Builder {
			public Builder names(String... names) {
				this.names = names;
				return this;
			}
			public Builder foramily(String... names) {
				this.farther = names[0];
				this.marther = names[1];
				return this;
			}
		}
		...
	}- 
유연하다. (e.g. 객체가 만들어질 때마다 자동적으로 증가하는 일련번호 같은 것을 채울 수 있다) 
- 
인자가 설정된 빌더는 훌륭한 [Abstract Factory][dp-abstract-factory]다. JDK1.5 이상을 사용하는 경우, 제네릭 자료형 하나면 어떤 자료형의 객체를 만드는 빌더냐의 관계 없이 모든 빌더에 적용할 수 있다. 
	public interface Builder<T> {
		public T build();
	}	public class Person {
		public static class Builder implements Builder<Person> {
			...
			public Person build() {
				return new Person(this);
			}
		}
	}**e.g.** *Code at package `java.util.stream`*
	Stream.builder().add(1).add(2).add(3).build();- 
빌더 객체를 인자로 받는 메서드는 보통 *한정적 와일드카드 자료형~bounded wildcard type~*을 통해 인자의 자료형을 제한한다([규칙 28](#items28)). 
	Tree buildTree(Builder<? extends Node> nodeBuilder) {...}- 
자바가 제공하는 추상적 팩토리로는 Class 객체가 있으며, 이 객체의 newInstance() 가 build 메서드 구실을 한다. **하지만,** newInstance()는 항상 무인자 생성자를 호출하려 하는데, 문제는 그런 생성자가 없을 수도 있다는 것. TO-DO 
문제점
- 
빌더 객체를 만드는 오버헤드가 문제가 될 수 있다(성능이 중요한 상황). 그러니 인자 갯수가 통제할 수 없을 정도로 많아지만 빌더 패턴을 적용하자. 
요약
빌더 패턴은 인자가 많은 생성자나 정적 팩터리가 필요한 클래스를 설계할 때, 특시 대부분의 인자가 선택적 인자인 상황에 유용하다.
| Tip | lombok 활용하여 빌더 만들기  |