본문 바로가기

프로그래밍/JAVA

[JAVA] Effective Java - 2. 점층적 생성자, 자바 빈즈, 빌더 패턴

반응형

매개변수가 많다면 빌더를 고려하라

 

매개변수의 수가 많으면 기존 정적 팩터리 메서드와 생성자 모두 대응이 어려움.

이때, 기존 대응 방법과 한계를 먼저 설명.

 

1. 점층적 생성자 패턴

class Order {

  private String first; // 필수
  private String second; // 필수
  private String third; // 선택
  private String fourth; // 선택

  public Order() {
  }

  public Order(String first, String second) {
    this(first, second, null, null);
  }

  public Order(String first, String second, String third) {
    this(first, second, third, null);
  }

  public Order(String first, String second, String third, String fourth) {
    this.first = first;
    this.second = second;
    this.third = third;
    this.fourth = fourth;
  }
}

 

필수 매개변수만 받는 생성자 부터 시작하여 매개변수를 1개씩 더 받는 생성자를 점층적으로 늘려 작성한다.

사용자는 자신이 필요하고 가장 적은 매개변수를 가진 생성자를 선택하여 사용한다.

이럴 경우 사용자는 자신이 필요없는 매개변수도 지정해줘야하고, 매개변수가 더 많아지면 코드 작성이나 읽기가 어렵다.

 

2. 자바빈즈 패턴 (JavaBeans)

class Order {

  private String first; // 필수
  private String second; // 필수
  private String third; // 선택
  private String fourth; // 선택

  public Order() {
  }

  public void setFirst(String first) {
    this.first = first;
  }

  public void setSecond(String second) {
    this.second = second;
  }

  public void setThird(String third) {
    this.third = third;
  }

  public void setFourth(String fourth) {
    this.fourth = fourth;
  }
}

 

매개변수가 없는 생성자를 만들고, 각 세터(Setter) 메서드들을 만들어 원하는 매개변수를 세팅하는 방법.

Order order = new Order();
order.setFirst("1");
order.setSecond("2");
order.setThird("3");
order.setFourth("4");

이전 점층적 생성자 방식보다 코드는 길어졌지만, 생성과 읽기가 쉬움.

하지만 객체 하나를 생성하려면 여러번 메서드를 호출해야 하고,  스레드 안정성을 얻으려면 추가작업이 필요

그리고 객체가 완전히 생성되기 전까지는 객체의 일관성이 무너진 상태

여기서 일관성이 무너진 상태란 객체의 모든 매개변수가 세팅되기 전 까지는 객체의 상태는 일관되지 않다는 뜻

  -> order.setFirst("1"); 을 실행하고 난 뒤 객체와, order.setSecond("2"); 를 실행하고 난 뒤의 객체는 일관되지 않음.

Setter 메서드가 열려 있으므로 언제든지 일관성은 무너질 수 있다.

즉 자바빈 패턴으로는 불변객체를 만들수 없음.

 

불변객체의 예

class Order {

  private final String first;
  private final String second;
  private final String third;
  private final String fourth;

  public Order(String first, String second, String third, String fourth) {
    this.first = first;
    this.second = second;
    this.third = third;
    this.fourth = fourth;
  }
  // Setter X
  public String getFirst() {
    return first;
  }

  public String getSecond() {
    return second;
  }

  public String getThird() {
    return third;
  }

  public String getFourth() {
    return fourth;
  }
}

 

3. 빌더 패턴 (Builder)

점층적 생성자 패턴의 안정성과 자바빈즈 패턴의 가독성을 모두 겸비함.

class Order {

  private String first;
  private String second;
  private String third;
  private String fourth;


  public Order(Builder builder) {
    this.first = builder.first;
    this.second = builder.second;
    this.third = builder.third;
    this.fourth = builder.fourth;
  }

  public static Builder builder() {
    return new Builder();
  }

  public static class Builder {

    private String first;
    private String second;
    private String third;
    private String fourth;

    public Builder() {
    }

    public Builder first(String first) {
      this.first = first;
      return this;
    }

    public Builder second(String second) {
      this.second = second;
      return this;
    }

    public Builder third(String third) {
      this.third = third;
      return this;
    }

    public Builder fourth(String fourth) {
      this.fourth = fourth;
      return this;
    }

    public Order build() {
      return new Order(this);
    }
  }
}

사용자는 직접 객체를 생성하지않고, 빌더 객체를 얻어 빌더 객체가 제공하는 Setter 메서드를 통해

원하는 매개변수를 설정하고, build 메서드를 통해 최종적으로 객체를 얻는다.

이때 얻은 객체는 보통 불변객체 이다. (Setter X)

Order order = Order.builder().first("1").second("2").build(); // 불변객체

빌더의 Setter 메서드들은 빌더 자신을 반환하기 때문에 연쇄적으로 호출 가능 (메서드 연쇄)

코드는 쓰기 쉽고, 가독성도 훨씬 좋다.

단점으로는 객체 생성시 빌더를 만들어야한다. 생성비용이 크지않지만 성능에 민감하다면 문제가 될 수 있다.

코드가 장황해져서 매개변수가 4개 이상일때, 쓰는게 좋다

 

반응형