⚙ object의 타입이나 속성을 컴파일 하는 시점에 모른다고 했을 때 팩토리 factory method 패턴을 사용해서 런타임이나 생성주기안에서 다이나믹하게 생성 할 수 있도록 도와준다.
e.g.
API 데이터 페칭하고 결과에 따라 동적으로 무언가를 구현해야 할 때,
특히 반복적으로 무언가를 만들어내야 할 때 사용된다.
data.ts
export interface Data {
type: string;
attr: { name: string; size: number };
}
export const data: Data[] = [
{ type: "Nike", attrs: { name: "a", size: 250 } },
{ type: "Nike", attrs: { name: "b", size: 240 } },
{ type: "Puma", attrs: { name: "c", size: 230 } },
{ type: "Adidas", attrs: { name: "d", size: 220 } },
{ type: "Nike", attrs: { name: "e", size: 260 } },
];
index.ts
import { Data } from "./data";
interface Attrs {
name?: string;
size?: number;
brand?: string;
}
class Shoe {
private _attrs: Attrs;
constructor(attrs?: Attrs) {
this._attrs = attrs || {};
}
getName() {
return this._attrs?.name;
}
getSize() {
return this._attrs?.size;
}
getBrand() {
return Object.getPrototypeOf(this).constructor.name;
}
}
// Shoe라는 base class를 상속받는다.
class Nike extends Shoe {}
class Adidas extends Shoe {}
class Puma extends Shoe {}
// factory class
class ShoeFactory {
// 조건을 담당하는 object
typeMap: { [key: string]: typeof Shoe } = {
nike: Nike,
puma: Puma,
adidas: Adidas,
};
// create
// 액션 함수, 객체 생성을 담당한다.
// typeMap 객체를 활용해서 어떤 타입의 class를 생성할 지 선택한 후에 Brand라는 변수에 저장하고 Brand 변수를 생성자 함수로 호출한다.
create(props: Data) {
try {
const Brand = this.typeMap[props?.type?.toLowerCase()];
return new Brand(props.attrs);
} catch (e) {
console.error("error creating new shoes", e);
}
}
}
// test
const factory = new ShoeFactory();
const nike1 = factory.create({
type: "Nike",
attrs: { name: "kkk", size: 260 },
});
console.log(nike1);
결과
Nike class가 생성되었고 instance를 반환받았다.
상속된 함수들 test
console.log(nike1?.getBrand());
console.log(nike1?.getSize());
결과
map
함수 이용한 test
const items = data.map((item) => factory.create(item));
console.log(items);
결과
data를 바탕으로 각자 다른 타입의 class가 생성된 것을 볼 수 있다.
참고 자료