Search
♻️

[디자인 패턴 - 생성 패턴] 추상 팩토리 패턴 (Abstract Factory)

1. 의도

상세화된 구상 클래스(실제 구현체)에 의존하지 않고도, 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스 제공
구상 클래스는 서브클래스에서 만듦

2. 활용성

GoF
객체가 생성되거나 구성 및 표현되는 방식과 무관하게 시스템을 독립적으로 만들고자 할 때
여러 제품군 중 하나를 선택해서 시스템을 설정해야하고, 한번 구성한 제품을 다른 것으로 대체할 수 있을 때
관련된 제품 객체들이 함께 사용되도록 설계되었고, 이부분에 대한 제약이 외부에도 지켜지도록 하고 싶을 때
제품에 대한 클래스 라이브러리를 제공하고, 그들의 구현이 아닌 인터페이스를 노출 시키고 싶을 때
Head First
구상 클래스에 직접 의존하지 않고도 서로 관련된 객체로 이루어진 제품군을 만드는 용도로 쓰임
팩토리는 구상 클래스가 아닌 추상 클래스와 인터페이스에 맞춰서 코딩할 수 있게 하는 강력한 기법
팩토리 패턴은 애플리케이션의 구상 클래스 의존성을 줄여줌으로써 느슨한 결합을 도와 줌
객체 생성을 캡슐화 할 수 있음

3. 구조

UML Class Diagram

4. 참여자

참여자
역할
예시
AbstractFactory
개념적 제품에 대한 객체를 생성하는 인터페이스
피자 재료 제조 공장 (주방)
ConcreteFactory
구체적인 제품에 대한 객체를 생성 담당. AbstractFactory 를 구현
피자 재료 제조 실제 공장 (시카고, 뉴욕 피자 재료 공장)
AbstractProduct
개념적 제품 객체에 대한 인터페이스
피자 재료 (도우, 소스, 야채)
ConcreteProduct
구체적으로 팩토리가 생성할 객체 정의. AbstractProduct 를 구현
피자 실제 재료 (두꺼운/얇은 도우, 토마토/크림 소스, 콤비네이션/베지 야채)
Client
AbstractFactoryAbstractProduct 클래스에 선언된 인터페이스 사용
피자 가게

5. 협력 방법

ConcreteFactory 클래스의 인스턴스가 1개 런타임에 생성됨 (예. NYPizzaIngredientFactory)
ConcreteFactory는 어떤 특정 구현을 갖는 제품 객체를 생성
서로 다른 제품 객체를 생성하려면 사용자는 서로 다른 구체 팩토리 사용 필요
AbstractFactory는 필요한 제품 객체를 생성하는 책임을 ConcreteFactory에 위임

6. 결과

구체적인 클래스 분리
응용 프로그램이 생성할 객체의 클래스를 제어할 수있음
팩토리는 제품 객체를 생성하는 과정과 책임을 캡슐화 → 구체적인 구현 클래스가 사용자에게서 분리
제품 클래스 이름이 구체 팩토리 구현에서 분리되므로 사용자 코드에는 나타나지 않음
제품군 쉽게 대체 가능
응용 프로그램이 사용할 구체 팩토리 변경 용이
제품 사이의 일관성 증진
새로운 종류의 제품 제공이 어려움
새로운 종류의 제품이 등장시, 팩토리 구현 변경 필요

7. 예시 코드

// 실제 호출 코드 const pizzaStore = new PizzaStore(); const NYPizza = pizzaStore.createPizza(new NYPizzaIngredientFactory()); console.log(NYPizza); const ChicagoPizza = pizzaStore.createPizza(new ChicagoPizzaIngredientFactory()); console.log(ChicagoPizza);
TypeScript
복사
// 팩토리 코드 interface PizzaIngredientFactory { createDough(): AbstractDough; createSauce(): AbstractSauce; createVeggies(): AbstractVeggies; } class NYPizzaIngredientFactory implements PizzaIngredientFactory { public createDough(): AbstractDough { return new ThickCrustDough(); } public createSauce(): AbstractSauce { return new TomatoSauce(); } public createVeggies(): AbstractVeggies { return new CombinationVeggies(); } } class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory { public createDough(): AbstractDough { return new ThinCrustDough(); } public createSauce(): AbstractSauce { return new CreamSauce(); } public createVeggies(): AbstractVeggies { return new VegetarianVeggies(); } } class PizzaStore { public createPizza(ingredient: PizzaIngredientFactory) { const dough = ingredient.createDough(); const sauce = ingredient.createSauce(); const veggies = ingredient.createVeggies(); return { dough: dough.getDough(), sauce: sauce.getSauce(), veggies: veggies.getVeggies(), }; } }
TypeScript
복사
// 프로덕트 코드 interface AbstractDough { getDough(): string; } class ThickCrustDough implements AbstractDough { public getDough(): string { return 'thick crust dough'; } } class ThinCrustDough implements AbstractDough { public getDough(): string { return 'thin crust dough'; } } interface AbstractSauce { getSauce(): string; } class TomatoSauce implements AbstractSauce { public getSauce(): string { return 'tomato sauce'; } } class CreamSauce implements AbstractSauce { public getSauce(): string { return 'cream sauce'; } } interface AbstractVeggies { getVeggies(): string; } class CombinationVeggies implements AbstractVeggies { public getVeggies(): string { return 'combination veggies'; } } class VegetarianVeggies implements AbstractVeggies { public getVeggies(): string { return 'vegetarian veggies'; } }
TypeScript
복사