[이펙티브 자바] 생성자에 매개변수가 많다면 빌더를 고려하라_아이템2
[점층적 생성자 패턴(telescoping constructor pattern)]
필수 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자 등등 경우의 수만큼 받는 생성자를 늘려가는 방식이다.
[점층적 생성자 패턴 예제]
//점층적 생성자 패턴
public class reservation{
private final int reseDate; //날짜(필수)
private final String reseProgramNm; //예약프로그램명(필수)
private final String reseNm; //예약자명(필수)
private final String reseWithNm; //동행자(선택)
private final String coupon; //쿠폰사용(선택)
public reservation(int reseDate, String reseProgramNm, String reseNm){
this(reseDate, reseProgramNm, reseNm, “0”);
}
public reservation(int reseDate, String reseProgramNm, String reseNm, String reseWithNm){
this(reseDate, reseProgramNm, reseNm, reseWithNm, “0”);
}
public reservation(int reseDate, String reseProgramNm, String reseNm, String reseWithNm, String coupon){
this.reseDate = reseDate;
this.reseProgramNm = reseProgramNm;
this.reseNm = reseNm;
this.reseWithNm = reseWithNm;
this.coupon = coupon;
}
public static void main(String[] args){
reservation rese = new reservation(20231107, “피부테라피”, “한지민”, “김이나”, “Y”);
System.out.println(rese);
}
}
사용할 매개변수를 모두 포함한 생성자를 골라서 사용하면된다. 하지만 위에 예제는 매개변수가 적지만 많은 매개변수를 사용하는 프로그램에서는 수가 많아지면 걷잡을 수 없기 때문에 좋은 방법은 아니다.
클라이언트가 실수로 매개변수의 순서를 바꿔 건네줘도 컴파일러는 알아채지 못하고, 런타임에 엉뚱한 동작을 하게된다.
[자바빈즈 패턴(JavaBeans pattern)]
매개변수가 없는 생성자로 객체를 만든 후, 세터 메서드들을 호출해 원하는 매개변수의 값을 설정하는 방식이다.
[자바빈스 패턴 예제]
//자바빈즈 패턴
public class reservation {
private int reseDate = 0; //날짜(필수)
private String reseProgramNm = ""; //예약프로그램명(필수)
private String reseNm = ""; //예약자명(필수)
private String reseWithNm = ""; //동행자(선택)
private String coupon = "N"; //쿠폰사용(선택)
public reservation() {}
//세터 메서드들
public void setReseDate(int val) {reseDate = val;}
public void setReseProgramNm(String val) {reseProgramNm = val;}
public void setReseNm(String val) {reseNm = val;}
public void setReseWithNm(String val) {reseWithNm = val;}
public void setCoupon(String val) {coupon = val;}
public static void main(String[] args){
reservation rese = new reservation();
rese.setReseDate(20231107);
rese.setReseProgramNm("피부테라피");
rese.setReseNm("한지민");
rese.setReseWithNm("김이나");
rese.setCoupon("Y");
System.out.println(rese);
}
}
단점은 객체 하나를 만들려면 메서드를 여러개 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성(consistency)이 무너진 상태에 놓이게 된다.
일관성이 무너지면 클래스를 불변으로 만들 수 없고, 스레드 안전성을 얻으려면 프로그래머가 추가 작업을 해야한다.
[빌더 패턴(Builder pattern)]
점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 겸비하고있다.필수 매개변수만으로 생성자를 호출해 빌더 객체를 얻고, 제공하는 세터 메서드를 원하는 선택 매개변수들을 설정한 후 마지막 매개변수없는 build 메서드를 호출하여 객채를 얻는다.
[빌더 패턴 예제]
//빌더 패턴
public class reservation {
private final int reseDate; //날짜(필수)
private final String reseProgramNm; //예약프로그램(필수)
private final String reseNm; //예약자명(필수)
private final String reseWithNm; //동행자(선택)
private final String coupon; //쿠폰사용(선택)
public static class Builder{
//필수 매개변수
private final int reseDate; //날짜(필수)
private final String reseProgramNm; //예약프로그램(필수)
private final String reseNm; //예약자명(필수)
//선택 매개변수 - 기본값으로 초기화한다.
private String reseWithNm = ""; //동행자(선택)
private String coupon = "N"; //쿠폰사용유무(선택)
public Builder(int reseDate, String reseProgramNm, String reseNm) {
this.reseDate = reseDate;
this.reseProgramNm = reseProgramNm;
this.reseNm = reseNm;
}
public Builder reseWithNm(String val) {
reseWithNm = val;
return this;
}
public Builder coupon(String val) {
coupon = val;
return this;
}
public reservation build() {
return new reservation(this);
}
}
private reservation(Builder builder) {
reseDate = builder.reseDate;
reseProgramNm = builder.reseProgramNm;
reseNm = builder.reseNm;
reseWithNm = builder.reseWithNm;
coupon = builder.coupon;
}
public static void main(String[] args) {
reservation rese = new reservation.Builder(20231107, "피부테라피", "한지민")
.reseWithNm("김이나").coupon("Y").build();
System.out.println(rese);
}
}
예약클래스는 빌더의 세터 메서드들의 빌더 자신을 반환하기 때문에 연쇄적으로 흐른다는 뜻으로 메서드 연쇄(method chaining)라 한다.
빌더 패턴은 계층적으로 설계된 클래스와 함께 쓰기 좋다. 빌더를 사용하면 가변인수(varargs) 매개변수를 여러개 사용할 수 있다. 빌더 패턴은 상당히 우연하고, 하나로 여러 객체을 순회하면서 만들 수 있다. 객체마다 부여되는 일련번호와 같은 특정 필드는 빌더가 알아서 채우도록 할 수도 있다.
단점은 빌더부터 만들어야하고, 생성 비용이 크지는 않지만 성능에 민감한 상황에서는 문제가 될 수 있다. 생성자나 정적 펙털 방식으로 시작했다가 나중에 매개변수가 많아져 빌더 패턴으로 전환할 수도 있다. 이렇게 전환되는 상황보단 애초에 빌더로 시작하는 편이 나을 때가 많다.