책/이펙티브 자바
item 2 생성자에 매개변수가 많다면 빌더를 고려하라
함께자라기
2022. 2. 10. 20:47
ITEM 2 생성자에 매개변수가 많다면 빌더를 고려하라
정적 팩터리 패턴과 생성자는 매개변수가 많을 때 가독성이 떨어지게 된다
이럴때 점층적 생성자 패턴, 자바 빈즈 패턴, 빌더 패턴을 사용해보자
점층적 생성자 패턴
public class Foo {
private String userName; //필수값
private int age; //필수값
private String address; //필수값
private String tel; //선택값
public Foo(String userName) {
this.userName = userName;
}
public Foo(String userName, int age) {
this.userName = userName;
this.age = age;
}
public Foo(String userName, int age, String address) {
this.userName = userName;
this.age = age;
this.address = address;
}
public Foo(String userName, int age, String address, String tel) {
this.userName = userName;
this.age = age;
this.address = address;
this.tel = tel;
}
}
장점
- 매개변수의 개수에 따라 생성자가 점점 증가하는 방식이다
- 한번의 호출로 객체가 생성된다
단점
- 매개변수가 증가함에 따라 각 값의 순서나 개수등을 신경 써야한다
- 한눈에 의미를 파악하기가 어렵고 호출부의 가독성이 떨어지고 작성하기가 어려워진다
- 필수값이 아닌 값이라도 객체 생성을 위해 빈 값을 넣어줘야 한다
public static void main(String[] args) {
Foo foo = new Foo("hong");
Foo foo2 = new Foo("hong",10);
Foo foo3 = new Foo("hong",10,"대전");
Foo foo4 = new Foo("hong",10,"대전","");
}
자바 빈즈 패턴
public class FooJavaBeans {
private String userName;
private int age;
private String address;
private String tel;
public void setUserName(String userName) {
this.userName = userName;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public void setTel(String tel) {
this.tel = tel;
}
}
장점
- 기본 생성자 하나만 만들고 set 메서드를 통하여 값을 셋팅해준다
- 점층적 생성자 패턴보다 가독성이 좋다
- 점층적 생성자 패턴보다 확장하기가 편하다
단점
- 한번의 호출로 객체 생성이 끝나지 않기 때문에 일관성이 무너진 상태가 된다
- setter가 존재 하기에 불변으로 만들수 없어 쓰레드 안정성을 위해 추가적인 작업이 필요하다
- 점층적 생성자 패턴과 다르게 매개변수의 유효성 체크가 즉각적으로 이루어지지 않는다
public static void main(String[] args) {
FooJavaBeans fooJavaBeans = new FooJavaBeans();
fooJavaBeans.setUserName("hong");
fooJavaBeans.setAge(10);
fooJavaBeans.setAddress("대전");
fooJavaBeans.setTel("");
}
빌더 패턴
package chapter2.item2;
public class FooBuilder {
private final String userName;
private final int age;
private final String address;
private final String tel;
public static class Builder {
private final String userName; //필수값
private final int age; //필수값
private final String address; //필수값
private String tel; //선택값
public Builder(String userName, int age, String address) {
this.userName = userName;
this.age = age;
this.address = address;
}
public Builder tel(String tel) {
this.tel = tel;
return this;
}
public FooBuilder build() {
return new FooBuilder(this);
}
}
private FooBuilder(Builder builder) {
userName = builder.userName;
age = builder.age;
address = builder.address;
tel = builder.tel;
}
}
장점
- 점층적 생성자 패턴과 자바 빈 패턴의 장점을 합쳤다(불변성 + 가독성)
- 호출부 코드를 메서드 체이닝으로 작성하여 가독성이 좋아졌다
- 점층적 생성자 패턴처럼 객체의 일관성도 보장되며 객체 생성시 필수값 지정도 가능하다
- 빌더 하나로 여러 객체를 순회하며 만들 수 있다
- 매개변수에 따라 다른 객체를 생성 할수도 있으므로 유연성이 높다
단점
- 클래스 내부에 빌더를 추가로 만들어 주는 작업이 필요하기 때문에 필수 매개변수가 많다면 생각이 좀 필요하다
- 어쨋거나 빌더를 추가로 만드는 것익이 때문에 성능에 민감하다면 생각을 좀 해봐야 한다
public static void main(String[] args) {
FooBuilder fooBuilder = new FooBuilder.Builder("hong",10,"대전")
.tel("01012345678")
.build();
}
불변(immutable) 과 불변식(invariant)
- 불변
- 변경을 할수 없다는 뜻, 대표적으로 String이 있다
- 불변식
- 프로그램이 실행중, 정해진 일정 기간동안 만족해야 하는 조건이다
- 변경 허용이 가능하지만 특정 조건내에서만 가능하다