TypeScript에 생성자 대신 정적 팩토리 메서드를 고려해보자

안지환·2024년 4월 14일

공부 기록

목록 보기
4/5

팀 프로젝트를 시작 하기 전 백엔드 팀원들에게 정적 팩토리 메서드 설명하기 위한 글입니다.

<<Effective Java 3/E>> 첫 단원 시작 할 때부터 생성자 대신 정적 팩터리 메서드를 고려하라 라는 단원이 시작됩니다.
Java에 익숙한 개발자는 정적 팩터리 메서드를 한번쯤은 들어 볼 것입니다. 주로 DTO 클래스에 정적 팩터리 메서드를 정의하여 of 형태의 메서드로 객체 생성을 반환하는 개발을 합니다.

왜? 정적 팩토리 메서드를 사용하면 좋은지 설명해드리겠습니다.

1. 정적 팩토리 메서드와 Public 생성자와 무엇이 다를까?

클래스로 선언하고 해당 클래스의 인스턴스를 얻기 위해서는 클래스 내부에 Public 생성자를 선언합니다.
클라이언트가 클래스 인스턴스를 얻기 위해서는 new 예약어를 선언하고 해당 클래스를 호출합니다.

// 클래스 정의
export class User {
  private email: string;
  private password: string

  constructor(email: string, password: string) {
   this.email = email;
   this.password = password;
  }
  
  // Getter Setter
  ...
}

// 클래스 인스턴스 호출
const user = new User('abc@email.com', '123456');

user.getEmail()
user.getPassword()

이 형태의 일반적인 클래스 호출 방법입니다.

하지만 정적 팩터리 메서드를 사용한다면 어떤 형태일지 설명하겠습니다.
정적 팩토리 메서드는 new 예약어 없이 클래스를 선언 후 static 정적 메서드를 선언 후 클래스의 인스턴스를 반환하는 형태 입니다.

export class User {
  private email: string;
  private password: string

  constructor(email: string, password: string) {
   this.email = email;
   this.password = password;
  }

  static createUser({ email, password}: { email: string, password: string}) {
  return new User(email, password);
  }
  
  // Getter Setter
  ...
}

// 정적 팩토리 메서드
User.create({ email: user.getEmail(), password: user.getPassword()})

클래스 인스턴스를 호출할 때 클래스 메서드를 호출하여 객체를 반환합니다.

둘 차이점은 분명하지만 정적 팩터리 메서드 장단점을 설명하겠습니다.

2. 정적 팩토리 메서드 장점

Public 생성자와 정적 팩터리 메서드를 비교 시 장점은 간략하게 나열하자면 다음과 같습니다.

  • 반환 객체의 특성에 따라 이름을 지정할 수 있습니다.
  • 매번 인스턴스를 생성 할 필요가 없습니다.
  • 매개변수에 따라 클래스의 객체를 다르게 반환 할 수 있습니다.

클래스 인스턴스를 호출 시 Public 생성자를 사용한다면 생성자 자체만으로 반환될 객체의 특성을 제대로 설명하기가 어렵습니다.
예를 들어 "User의 이메일 정보를 반환한다"는 의미를 생성자와 정적 팩터리 메서드 두 개의 코드를 보여주겠습니다.

// 생성자 
const member = new Member("abc@gmail.com") 
member.getEmail()

// 정적 팩터리 메서드
Member.getEmail(email)

코드를 살펴보면 정적 팩토리 메서드로 작성할 때 의도를 이해하기가 쉽습니다.

두 번째 장점으로는 인스턴스를 새로 생성하지 않아도 된다는 점입니다.
Member.getEmail(email) 메서드는 객체를 불러오는 것이 아니라 미리 정의 한 객체를 메서드로 불러오는 형태라 객체를 새로 생성하지 않습니다.
덕분에 성능에 상당한 이점을 얻을 수 있습니다. 대표적으로 싱글톤을 패턴을 만들 수도 있고 불변 클래스를 만들 수도 있습니다.

세 번째 장점은 매개변수의 수에 따라 객체를 다르게 반환 할 수 있습니다.
매개변수에 따라 생성자를 그에 맞게 생성해야 합니다. 그렇지만 정적 팩터리 메서드는 매개변수에 형태에 따라 메서드 명을 정의 할 수 있어 의도를 분명하게 드러 날 수 있고 메서드명만 알면 내부 구조를 몰라도 되는 은닉화를 할 수 있습니다.

Member.of(email, password)
Member.from(password)
...

3. 정적 팩토리 메서드 단점

단점은 상속에 대해서 유연하게 처리 할 수 없는 문제가 발생합니다.
클래스간의 상속에서는 생성자가 필요하지만 정적 팩터리 메서드는 생성자가 아님으로 상속을 할 수가 없습니다.

두번째는 이 형태에 익숙하지 않은 개발자가 사용한다면 혼란을 야기 시 킬 수 있습니다.
개발 스타일이 정적 팩터리 메서드를 활용하지 않고 개발을 진행 해왔다면 생소함을 가질 수 있습니다.
메서드 명명 규칙을 모르는 상태에서는 어떤 메서드 명이 올바른지를 알 수가 없습니다.

4. 정적 팩토리 메서드을 사용해도 될까?

장단점과 정적 팩터리 메서드 정의를 알아봤습니다. 이 글은 Java 가 아닌 TypeScript 개발을 진행하려는 개발자에게 설명하기 위해서 쓴 글입니다.
그렇기 때문에 정적 팩터리 메서드를 사용하자고 한다면 당장 혼란을 만들 수 있습니다. TypeScript가 Java에 static 과 비슷할까? 라는 의문을 가질 수 있습니다.
필자도 Java에서 TypeScript로 넘어 왔을 때 언어 환경이 다르다보니 개발 스타일도 다를 것이라고 생각 했었습니다.
그렇지만 TypeScript에서도 Java에서 활용했던 정적 팩토리 메서드 기법을 사용할 수 있다는 것을 알게 되었습니다.
때문에 걱정 할 필요 없이 여러 기법을 활용 할 수 있습니다.

profile
BackEnd Developer

0개의 댓글