본문 바로가기

Node.js

정적 팩토리 메서드

정적 팩토리 메서드(static factory method)

객체 생성 역할을 하는 클래스 메서드. 생성자를 통해 직접적으로 객체를 생성하는 것이 아니라 메서드를 통해 객체를 생성한다. 생성자를 활용하여 객체를 생성하는 것과 어떤 차이가 있는가?

 

1. 이름을 가질 수 있다.
객체는 생성 목적과 과정에 따라 생성자를 구별해서 사용할 필요가 있다. 
new 키워드를 통해 객체를 생성하는 것은 내부구조를 잘 알고 있어야 목적에 맞게 객체를 생성 할 수 있다.
하지만 정적 팩토리 메서드를 사용하면 메서드 이름에 객체의 생성 목적을 담을 수 있다.

2. 호출 할 때마다 새로운 객체를 생성할 필요가 없다.
대표적인 예로 enum과 같이 자주 사용되는 요소의 개수가 정해져있다면 해당 개수만큼 미리 생성해놓고 조회할 수 있는 구조로 만들 수 있다.
미리 생성된 객체의 캐싱을 통해 새로운 객체 생성의 부담을 덜 수 있는 장점도 있지만, 생성자의 접근 제한자를 private로 설정해 객체 생성을 정적 팩토리 메서드로만 가능하도록 제한 할 수 있다.

3. 하위 자료형 객체를 반환 할 수 있다.
하위 자료형 객체를 반환하는 정적 팩토리 메서드의 특징은 상속을 사용할 때 확인할 수 있다.
이는 생성자의 역할을 하는 메서드가 반환값을 가지고 있기 때문에 가능한 특징이다. 조건에 따라 분기처리를 통해 각각 다른 하위 타입의 개체를 반환 할 수 있다.

4. 객체 생성을 캡슐화 할 수 있다.
정적 팩토리 메서드는 객체 생성을 캡슐화 하는 방법이기도 하다. 예를 들면 DTO 생성이 있다.
DTO와 Entity간에는 자유롭게 형 변환이 가능해야 하는데 정적 팩토리 메서드를 사용하면 내부 구현을 모르더라도 쉽게 변환할 수 있다.

 

typescript에서는 대략 이런 모습이다.

class CarDto {
  private name: string;
  private position: number;

  private constructor(name: string, position: number) {
    this.name = name;
    this.position = position;
  }

  public static from(car: Car) {
    return new CarDto(car.getName(), car.getPosition());
  }
}

const carDto = CarDto.from(car);


정적 팩토리 메서드는 단순히 생성자의 역할을 대신하는 것을 넘어 가독성 좋은 코드를 작성하고 객체지향적으로 프로그래밍 할 수 있도록 도와준다.


만약 도메인에서 객체 생성의 역할 자체가 중요한 경우, 정적 팩토리 클래스를 따로 분리하는 것도 방법이 된다. 그러나 팩토리 메서드만 존재하는 클래스를 생성할 경우 상속이 불가능한 단점이 있다.

생성자 내부에서는 this binding 시 async - await과 같은 비동기 처리가 불가능하다.
대표적으로 DB초기화 - DB반환 등 순차실행이 필요한 경우 비동기 처리를 완료하고 그 결과가 적용된 객체가 필요할 때도 정적 팩토리 메서드를 이용한다. 

정적 팩토리 메서드 네이밍 컨벤션
정적 팩토리 메서드를 만드는데 있어 일반적으로 이용되는 네이밍 컨벤션이 있다.

  • from: 하나의 매개 변수를 받아 객체를 생성
  • of: 여러개의 매개 변수를 받아 객체를 생성
  • getInstance | instance: 인스턴스 생성. 이전에 반환했던 것과 같을 수 있다
  • newInstance | create: 새로운 인스턴스를 생성
  • get[OtherType]: 다른 타입의 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있다
  • new[OtherType]: 다은 타입의 새로운 인스턴스를 생성.