개발하는 두더지

[Effective Java 규칙2] 생성자 인자가 많을 때는 Builder 패턴을 이용 본문

Java,Android

[Effective Java 규칙2] 생성자 인자가 많을 때는 Builder 패턴을 이용

덜지 2018. 9. 4. 16:57

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 구문이 완료될때까지 보장해준다(?) 맞는지 찾아보기


Comments