오늘 포스팅 할 내용은 Builder 패턴이다.

Class 를 설계하다 보면,

필수로 받아야 할 인자들이 있고,

선택적으로 받아야 할 인자들이 있는 경우가 있다.

필수적으로 받아야 할 인자를 받기 위해

생성자의 매개변수를 넣는다.

또한 선택적 인자를 받기 위해 추가적인

생성자를 만든다.


public class PersonInfo{

  private String name;         //필수적으로 받야할 정보

  private int age;                //선택적으로 받아도 되는 정보

  private int phonNumber;   //선택적으로 받아도 되는 정보

  public PersonInfo(String name){

     this.name = name;

  }

  public PersonInfo(String name, int age){

    this.name = name;

    this.age = age;

  }

  public PersonInfo(String name, int age, int phonNumber){

    this.name = name;

    this.age = age;

    this.phonNumber = phonNumber;

  }

}

이러한 상황을 Effective Java 2/E 에선 점층적 생성자 패턴이라 말한다.

하지만, 이러한 패턴은 잘 동작하지만, 몇가지 단점들이 존재한다.

첫번째로, 인자들이 많아 질 수록 생성자의 숫자 역시 많아진다.

두번째로, 매개변수의 이름으로 원하는 정보를 설명하지만,

같은 자료형은 실수로 바꿔 넣는 실수가 생길 수 있다.

예를 들어, 위의 예시에서 age와 phonNumber를 서로 바꿔 넣는 경우이다.

세번째로, 읽기 어려운 코드가 된다.

PersonInfo personInfo = new PersonInfo("Mommoo", 12, 119);

위의 코드는 매개변수의 정보를 설명할 수 없으므로,

personInfo 객체가 어떤 인자들이 들어갔는지 알기 위해선

PersonInfo 클래스의 매개변수 이름이나, 주석을 참고해야 한다.


이러한 단점들을 보완하기 위해, 자바 빈즈(beans) 패턴이 대안점으로 나온다.

해당 패턴은 웹프로그래밍을 할 때, 자주 쓰는 패턴이다.

public class PersonInfo{

  private String name;         //필수적으로 받야할 정보

  private int age;                //선택적으로 받아도 되는 정보

  private int phonNumber;   //선택적으로 받아도 되는 정보

  public PersonInfo(){

  }

  public void setName(String name){

    this.name = name;

  }

  public void setAge(int age){

    this.age = age;

  }

  public void setPhonNumber(int phonNumber){

    this.phonNumber = phonNumber;

  }

}

생성자의 단점으로 꼽혔던 가독성이 해당 패턴을 사용하는 경우, 어느정도 해결이 된다.

PersonInfo personInfo = new PersonInfo( );

personInfo.setName("Mommoo");         // 이름을 넣는 메서드

personInfo.setAge(12);                       // 나이를 넣는 메서드

personInfo.setPhonNumber(119);          // 전화번호를 넣는 메서드

자바빈즈 패턴은 코드량이 늘어나는 단점이 존재한다. 

하지만 그것보다 더욱 문제가 되는 것은 객체 일관성이 깨진다.

객체 일관성이 깨진다는 것이란, 한번 객체를 생성할때, 그 객체가 변할 여지가 존재한다는 뜻이다.

즉, set메서드는 언제 어디서든 사용 할 수 있다는 장점이 있지만, 객체의 불변성이 깨진다.

스레드 작업에 큰 단점이 될 수 있을 뿐더러, 컴파일러 오류는 아니지만, 우리가 원하지 않는

결과물이 만들어 질 수 있는것이다.


점층적 생성자패턴과 자바빈즈 패턴의 장점을 섞은것이 빌더패턴이다.

정보들은 자바 빈즈 패턴처럼 받되, 데이터 일관성을 위해 정보들을 다 받은후에 객체생성을 해준다.


public class PersonInfo{

  private String name;         //필수적으로 받야할 정보

  private int age;                //선택적으로 받아도 되는 정보

  private int phonNumber;   //선택적으로 받아도 되는 정보

  private PersonInfo(){

  }

  public static class Builder{

    private String name;

    private int age;

    private int phonNumber;

   

   public Builder(String name){

      this.name = name;

    }

   public Builder setAge(int age){

 this.age = age;

 return this;

   }

   public Builder setPhonNumber(int phonNumber){

 this.phonNumber = phonNumber;

 return this;

   }

   public PersonInfo build(){

   PersonInfo personInfo = new PersonInfo( );

   personInfo.name = name;

   personInfo.age = age;

   personInfo.phonNumber = phonNumber;

   return personInfo;

 }

}

이러한 빌더 패턴은 아래와 같이 사용한다.

PersonInfo personInfo = new Builder("Mommoo").setAge(12).setPhonNumber(119).build( );

setter에 리턴자료형을 Builder 객체를 지정함으로써, 메서드 체이닝 기법을 적용했고,

정보를 다 넣은 경우 build( ) 메서드로 객체생성을 한다.

build( ) 메서드를 쓴 이후 에는 PersonInfo 클래스의 멤버변수를 변경 할 수 있는 방법은

리플렉션 기법빼곤 존재하지 않는다. 따라서, 데이터 일관성, 객체불변성 등을 만족시킨다.

또한 코드 가독성 역시 올라간다.


하지만 이러한 빌드 패턴의 단점은 많은 코드량이 필요할 뿐더러,

Builder라는 객체를 하나더 만드는 것이므로, 때에 따라선 성능이 낮아질 수 있다.


Class 설계할때, 받아야할 인자들이 많거나, 선택적 인자들이 많거나 또한, 추가될 인자들이 많은 경우

에 Builder 패턴을 고려한다면, 좀 더 나은 설계를 할 수 있을 것이다.


포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

+ Recent posts