팩토리 패턴은 객체 지향 프로그래밍에서 유래된 디자인 패턴입니다.

객체 생성을 단순하게 추상화해서 반복적인 객체들을 생성할 때 사용합니다.

이 글에서는 제가 ES5, ES6+로 팩토리 패턴을 구현하는 몇가지 방법을 짧게 공유하겠습니다.

객체 생성자 함수

ES6에 클래스가 생기기 전에는 다음과 같은 객체 생성자 함수를 만들어서 클래스의 역할을 대신했습니다.

function Person(name) {
  this.name = name
}

var ashnamuh = new Person('ashnamuh')

console.log(ashnamuh.name) // ashnamuh

하지만 객체 생성 시 new 키워드를 실수로 빠뜨릴 수 있습니다. 만약 이런 경우 직접 객체를 생성하지 않는 팩토리가 유용할 수 있습니다.

다음처럼 생성자 함수에 정적 메소드를 추가해서 팩토리를 구현 가능합니다.

function Person(name) {
  this.name = name
}

Person.factory = function(name) {
  return new Person(name)
}

var ashnamuh = Person.factory('ashnamuh')

console.log(ashnamuh.name) // ashnamuh

객체 반환 함수

자바스크립트는 생성자로 객체를 생성하는 것 뿐만 아니라 다음과 같이 객체 리터럴 문법으로도 생성 가능합니다.

var ashnamuh = {
  name: 'ashnamuh'
}

console.log(ashnamuh.name) // ashnamuh

따라서 다음 예시처럼 객체를 반환하는 함수를 만들어서 팩토리를 구현할 수도 있습니다.

이 팩토리를 통해 생성된 객체들도 각각 다른 참조를 가집니다.

var personFactory = (name) => {
  return {
    name,
    say() {
      console.log('hello!')
    }
  }
}

var ashnamuh = personFactory('ashnamuh')
var jaemok = personFactory('jaemok')

console.log(ashnamuh.name) // ashnamuh
console.log(jaemok.name) // jaemok

console.log(ashnamuh === jaemok) // false

다른 타입의 생성자를 호출해서 반환하는 팩토리

위 두가지를 응용하면 다른 타입의 객체를 반환하는 팩토리도 쉽게 만들 수 있습니다.

생성자 함수를 별도로 만들고 type에 맞춰 객체를 생성해서 반환하는 팩토리입니다.

function Cat() {}

function Lion() {}

function animalFactory(type) {
  switch(type) {
    case 'Lion':
      return new Lion()

    case 'Cat':
      return new Cat()

    default:
      throw new Error('Invalid type!')
    }
}

var cat = animalFactory('Cat')
var lion = animalFactory('Lion')

ES6+ 클래스

ES6부터는 classextends(상속)이 생겨서 좀 더 쉽게 객체 지향 프로그래밍이 가능해졌습니다.

사실 ES5에서도 상속은 가능하지만, 프로토타입 체인을 연결하기가 번거롭습니다.

다음 예시처럼 위 생성자 함수를 클래스로 바꿔주기만 해도 어느정도 팩토리 구현이 가능합니다.

class Cat {}

class Lion {}

const animalFactory = (type) => {
  switch(type) {
    case 'Lion':
      return new Lion()

    case 'Cat':
      return new Cat()

    default:
      throw new Error('Invalid type!')
    }
}

const cat = animalFactory('Cat')
const lion = animalFactory('Lion')

혹은 다음처럼 상위 클래스에서 하위 클래스의 팩토리를 만들 수도 있습니다.

CatLion 클래스가 Animal 클래스를 상속받도록 했습니다.

class Animal {
  constructor() {
    this.type = 'animal'
  }

  static factory(type) {
    switch(type) {
      case 'Lion':
        return new Lion()

      case 'Cat':
        return new Cat()

      default:
        throw new Error('Invalid type!')
      }
  }
}

class Lion extends Animal {
  constructor() {
    super()
  }
}

class Cat extends Animal {
  constructor() {
    super()
  }
}

const lion = Animal.factory('Lion')
const cat = Animal.factory('Cat')

후기

자바스크립트로 간단하게 팩토리를 구현해보았습니다.

제가 구현하는 방식이라 이상한 점이 있을 수 있으니 지적은 환영합니다:)

자바스크립트는 멀티 패러다임 언어이지만 객체 지향적인 기능은 다른 언어에 비해 빈약합니다.

타입스크립트는 자바스크립트를 확장해서 추상클래스, 접근 제어자, 인터파에스, 데코레이더 등을 지원합니다.

아마 이를 사용한다면 Java에서 구현한 것처럼 팩토리를 구현할 수 있을거라 예상합니다.

타입스크립트로 팩토리 구현은 기회가 닿은다면 포스팅하겠습니다.

잘 읽어주셔서 감사합니다.