본문 바로가기
디자인패턴GoF/생성패턴

자바스크립트로 이해해보는 팩토리메소드패턴 (FactoryMethod Pattern) In 생성패턴

by 봉이로그 2023. 11. 3.

팩토리메소드패턴은 객체 생성을 하는 인터페이스를 만들어 추상화하고, 자식 클래스에서 상속받아 인터페이스를 구체화 한다고 할수 있다.

 

다수의 클래스와 객체가 존재할시에 추상화를 통해서, 반복적으로 생성되는 객체를 공장처럼 찍어낸다고 생각하면 된다.

 

즉, 클래스의 인스턴스를 직접 생성하는 대신, 추상화된 인터페이스를 통해 객체를 생성할수 있다.

 

클라이언트 코드는 구체적인 클래스의 생성 로직을 몰라도 된다.

 

대신에 추상화된 팩토리 메서드를 호출하여 객체를 생성하고 사용할 수 있다. 코드의 유용성과 재사용성을 올릴 수 있다.

 

옷공장을 만든다고 가정해보자.

export type ClothesType = "cardigan" | "jacket" | "shirts" | "pants";

export type DataType = {
  type: ClothesType;
  attrs: {
    brand: string;
    price: number;
  };
};

export const data: DataType[] = [
  { type: "cardigan", attrs: { brand: "발렌시아가", price: 50000 } },
  { type: "jacket", attrs: { brand: "스투시", price: 400000 } },
  { type: "shirts", attrs: { brand: "자크뮈스", price: 100000 } },
  { type: "pants", attrs: { brand: "르메르", price: 100000 } },
];

class Clothes {
  private _attrs: DataType["attrs"];

  constructor(attrs: DataType["attrs"]) {
    this._attrs = attrs;
  }

  getBrand() {
    return this._attrs.brand;
  }

  getPrice() {
    return this._attrs.price;
  }

  setPrice(price) {
    this._attrs.price = price;
  }
}

class Cardigan extends Clothes {
  걸치다() {}
}
class Jacket extends Clothes {
  걸치다() {}
}
class Shirts extends Clothes {
  잠구다() {}
  풀다() {}
}
class Pants extends Clothes {
  지퍼를잠구다() {}
  지퍼를풀다() {}
}

 

기본적으로 가장 기본이되는 옷이라는 클래스가 존재할 것이다.

 

그이후로, 종류별로 가디건 / 자켓 / 셔츠 / 팬츠 등등의 옷들이 추가되고 확장될 것이다.

 

먼저 Base가 되는 Clothes Class를 생성한다. 그리고 옷종류별로 Class들을 생성 하게된다.

 

class ClothesFacotry {
  typeMap = {
    cardigan: Cardigan,
    jacket: Jacket,
    shirts: Shirts,
    pants: Pants,
  };
  constructor() {}

  create1(_data: DataType) {
    const { type, attrs } = _data;
    if (type === "cardigan") {
      return new Cardigan(attrs);
    } else if (type === "jacket") {
      return new Jacket(attrs);
    } else if (type === "shirts") {
      return new Shirts(attrs);
    } else if (type === "pants") {
      return new Pants(attrs);
    }
  }

  create2(_data: DataType) {
    const { type, attrs } = _data;
    const ClothesType = this.typeMap[type];
    return new ClothesType(attrs);
  }
}

 

옷들을 생성하는 ClothesFactory 클래스를 생성한다. create 라는 옷클래스 생성함수를 만든다.

 

create1과 create2 메소드들은 만든거는 만드는 방식이 다양할수있어 소개해봤다.

 

공통적으로, type 유형에 따라 분류를 해서 객체를 생성한다고 볼수있다.

 

const clothesFactory = new ClothesFacotry();

const 하늘색가디건 = clothesFactory.create1({
  type: "cardigan",
  attrs: { brand: "아워레가시", price: 180000 },
});

console.log(하늘색가디건); // Cardigan { _attrs: { brand: '아워레가시', price: 180000 } }

const 옷무더기 = data.map((item) => new ClothesFacotry().create2(item));
console.log(옷무더기);

/*
[
    Cardigan { _attrs: { brand: '발렌시아가', price: 50000 } },
    Jacket { _attrs: { brand: '스투시', price: 400000 } },
    Shirts { _attrs: { brand: '자크뮈스', price: 100000 } },
    Pants { _attrs: { brand: '르메르', price: 100000 } }
  ]
*/

 

 

장점

- 확장에는 열려있고, 수정에는 닫혀있어 OCP를 위반하지 않는다. 

- 캡슐화하고 중앙 집중화할 수 있으므로 변경이 필요한 경우 코드 일부만 수정하여 쉽게 확장할 수 있다.

  - 클래스를 생성하고, create에 추가만 해주면된다.

- 객체 생성 및 초기화 로직을 한 곳에 유지하기 때문에 유지 보수가 복잡하지 않을수 있다.

- 테스트 용이: 팩토리메서드가 분리가 되어있어 해당부분만 테스트 가능

 

단점

- 추가적인 추상화 레이어(팩토리클래스)가 도입되므로 코드양이 많아지고, 복잡해질 수 있습니다.

- 간단한 경우에는 과도한 추상화가 필요하지 않을 수 있습니다.

- 추상화가 되어있어 코드파악이 어려울수있음