본문 바로가기
Javascript

자바스크립트 디자인패턴 - 빌더 패턴(Builder pattern)

by ttum 2021. 5. 18.

빌더 패턴(Builder pattern)이란?

빌더라는 이름처럼 객체를 생성하는 것에 관한 디자인 패턴이다.

객체를 만들어 사용하다 보면 간혹 객체 생성자가 너무 길어지거나 복잡해지는 경우가 생긴다. 이런 경우 빌더 패턴은 객체의 생성 과정을 분리해 순차적이고 직관적으로 만든다. 보너스로 객체를 Immutable하게 유지할 수도 있다.

 

특징

  • 👍 너무 길어지는 생성자를 피할 수 있음.
  • 👍 코드 가독성의 높임.
  • 👍 객체의 Immutability를 유지할 수 있음.
  • 👎 코드가 길어짐.

 

문제 상황

const user1 = new User('Andy', 10, null, 30);
const user2 = new User('June', 11, 150, null);
const user3 = new User('Gary', 10);

User 객체는 생성자 파라미터로 name, age, height, weight를 순서대로 받는다. 키와 몸무게를 밝히고 싶지 않은 사람들이 있으므로 두 정보는 선택적으로 적도록 한다. 이런 경우 몇 가지 불편한 점이 있다.

  • 매번 파라미터 순서를 체크해야함.
  • 파라미터의 개수가 늘어나면 실수할 가능성도 커짐.
  • 코드를 처음보는 사람은 숫자들이나 null이 의미하는 것을 직관적으로 파악할 수 없음.

만약 파라미터의 개수가 더 길어진다면 더욱 복잡해지며 실수할 가능성이 커지게 된다. 이런 문제 상황을 피하기 위해 빌더 패턴을 사용할 수 있다.

 

코드 구현

아래는 빌더 패턴을 이용해서 User 클래스를 만든 것이다. 이 클래스는 name과 age를 속성으로 가진다. 주목할 것은 Builder라는 static변수다. Builder 안에는 익명의 클래스가 들어있으며, 이 클래스는 User와 같은 속성들을 가진다. Builder 클래스 마지막에 build 함수에서 User 객체를 생성한다.

(#은 자바스크립트에서 private변수를 만드는 방법. 객체의 immutability를 유지하기 위해 사용함. constructor까지 private으로 만들어 사용하기 위해서는 typescript를 사용해야함.)

export default class User {
  #name;
  #age;
  constructor(builder) {
    this.#name = builder.getName();
    this.#age = builder.getAge();
  }

  getName() {
    return this.#name;
  }

  getAge() {
    return this.#age;
  }

  static Builder = class {
    #name = "";
    #age = 0;

    getName() {
      return this.#name;
    }

    setName(name) {
      this.#name = name;
      return this;
    }

    getAge() {
      return this.#age;
    }

    setAge(age) {
      this.#age = age;
      return this;
    }

    build() {
      return new User(this);
    }
  };
}

객체를 생성하는 방법은 아래와 같다. 이제는 height와 weight처럼 선택적으로 속성을 받는 경우에도 좋은 가독성을 유지할 수 있다.

const user = new User.Builder()
  .setName('kate')
  .setAge(15);

 

단점

첫 번째로 느낀 것은 코드가 굉장히 길어진다는 것이다. 특히 자바스크립트에서는 객체를 immutable하게 유지하기 위해 private 변수를 쓰는데, 그로 인해 코드의 양이 훨씬 늘어나게 된다. (get함수를 속성마다 만들어줘야 한다. private 변수를 사용하지 않으면 User 클래스의 contructor에서도 builder의 속성값들을 직접 불러올 수 있기 때문에 코드의 길이를 조금은 줄일 수 있다.)

두 번째는 길어진 코드 탓에 속성을 새로 추가하거나 제거하는 일이 번거로워질 수 있다는 점이다. 기존 클래스와 빌더 클래스를 모두 수정해줘야하기 때문이다.

 

느낀점

이런 몇 가지 단점에도 불구하고, 생성자 파라미터의 길이가 너무 길어진다면 빌더 패턴을 사용하는 것이 큰 도움이 될 것 같다. 가독성 면에서는 효과 짱짱이다.

typescript는 private constructor까지 확실히 지원하기 때문에, 완전한 캡슐화를 위해서는 typescript를 사용하는 것이 적합할 것 같다.