Search
moon
sun
♻️

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

Tags
Design Pattern
Architcture
Study
Last edited time
2023/04/15 04:45
2 more properties

1. 의도

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

2. 활용성

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

3. 구조

•
UML Class Diagram

4. 참여자

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

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
복사