[Effective Java 규칙2] 생성자 인자가 많을 때는 Builder 패턴을 이용
Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.
생성자에 인자가 많을 때 적용할 대안에는
1. 점층적 생성자 패턴
점층적으로 생성자를 쌓아가는 방식
class Car {
private int a;
private int b;
private int c;
private int d;
public Car(int a, int b) {
this(a, b, 0);
}
public Car(int a, int b, int c) {
this(a, b, c, 0);
}
public Car(int a, int b, int c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
}
2. 자바빈 패턴
빈 생성자를 만들고 Set 메서드를 만드는 방식
작성해야되는 코드는 많지만 개인적으로 읽기 쉬운 방식이라 생각함
단점
- 1회의 함수 호출로 객체 생성을 끝낼 수 없으므로 객체 일관성이 일시적으로 깨질 수 있다
- 변경 불가능(immutable) 클래스를 만들 수 없다
class Car {
private int a;
private int b;
private int c;
private int d;
public Car() {}
public void setA(int a) {
this.a = a;
}
public void setB(int b) {
this.b = b;
}
public void setC(int c) {
this.c = c;
}
public void setD(int d) {
this.d = d;
}
}
3. 빌더패턴
점층적 생성자 패턴의 안전성 + 자바빈 패턴의 가독성
인자가 많은 생성자나 정적 팩터리가 필요한 클래스를 설계할 때, 대부분의 인자가 선택적 인자인 경우에 유용하다
public class Car {
private int a;
private int b;
private int c;
private int d;
public static class Builder {
private int a = 0;
private int b = 0;
private int c = 0;
private int d = 0;
public Builder() { }
public Builder setA(int v) {
a = v;
return this;
}
public Builder setB(int v) {
b = v;
return this;
}
public Builder setC(int v) {
c = v;
return this;
}
public Builder setD(int v) {
d = v;
return this;
}
public Car build() {
return new Car(this);
}
}
private Car(Builder builder) {
a = builder.a;
b = builder.b;
c = builder.c;
d = builder.d;
}
}
Car car = new Car.Builder()
.setA(1)
.setB(2)
.setC(1)
.setD(2)
.build();
p 18 "1회의 함수 호출로 객체 생성을 끝낼 수 없으므로 객체 일관성이 일시적으로 깨질 수 있다" 라는 말은 set 함수를 여러군데에서 작성할 수 있으니 1회 호출로 끝낼 수 없다라는 말인가요?
-> 객체가 생성되고 생성자, 파라미터 set을 통해서 객체를 완성시키는데 set 도중 다른 값이 참조하게된다면 ( 다중스레드 등) 객체 일관성이 깨질 수 있다
즉 자바빈 패턴으로는 변경 불가능 (immutable) 클래스를 만들 수 없다. 보통 이런일이 발생할일이 없겠지만 가능성은 있다. 스레드 안정성을 제공하기 위해 해야할 일이 많다. 그래서 빌더 패턴이 이 단점을 보완해준다.
코틀린의 apply 은 객체.apply { 객체.value1 = 1} 등으로 사용하는데 apply는 객체가 만들어지고 synchronized 되어 apply 구문이 완료될때까지 보장해준다(?) 맞는지 찾아보기