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