추상 팩토리란?
서로 관련 있는 객체들(제품군)을 생성할 수 있는 팩토리들을 묶어서,
클라이언트가 구체적인 클래스에 의존하지 않고 제품군을 통일된 방식으로 만들 수 있도록 해주는 생성 패턴
이번에 추상 팩토리 패턴에 대해서 작성해보려고 한다.
또한 팩토리 메서드 패턴과 다른점이 무엇인지도 같이 다뤄보려고 한다!
https://dev-jiwonpark.tistory.com/24
디자인패턴 - 팩토리 메서드 패턴
추상 팩토리 패턴을 공부하다가.. 너무너무 이해가 안되는거다..도대체 이게 뭔데!? 를 반복하다가 팩토리 메서드 패턴을 먼저 공부해야 이해가 될것 같아 팩토리 메서드 패턴부터 공부해보려고
dev-jiwonpark.tistory.com
팩토리 메서드 패턴에서 다뤘던 비유는 커피 머신 이었다.
그럼 추상 팩토리 머신은 어떻게 비유할 수 있을까??
팩토리 메서드는 " 커피 한 잔 " 만 만들었다면 이제 손님이 커피 + 디저트 세트를 달라고 하는 것 과 같다.
그리고 그 원하는 세트 스타일은 아래 처럼 다양하다.
| 아메리카노 세트 | Americano | Cookie |
| 라떼 세트 | Latte | Muffin |
| 바닐라라떼 세트 | VanillaLatte | Cake |
위처럼 커피와 디저트가 서로 어울리도록 같은 세트 스타일로 만들어줘야 한다는 것이다.
이를 해결해줄 수 있는게 추상 팩토리 패턴이다!
미리 요약하자면..!
(1) 커피와 디저트를 묶어서 같은 스타일로 만들어주는 팩토리를 추상화한다.
(2) 클라이언트는 createCoffee()와 createDessert()만 호출하면 된다.
(3) 어떤 세트인지(아메리카노/라떼/바닐라)는 팩토리만 바꾸면 된다.
위의 개념을 이해할 수 있도록 아래에 예시를 보면서 같이 공부해보면 좋을 것 같다.
// abstract-factory-cafe.ts
// 1. 제품 인터페이스들
interface Coffee {
prepare(): string;
}
interface Dessert {
serve(): string;
}
// 2. 구체적인 커피들
class Americano implements Coffee {
prepare(): string {
return "아메리카노를 준비합니다: 에스프레소 + 물";
}
}
class Latte implements Coffee {
prepare(): string {
return "라떼를 준비합니다: 에스프레소 + 우유";
}
}
// 3. 구체적인 디저트들
class Cookie implements Dessert {
serve(): string {
return "쿠키를 제공합니다";
}
}
class Muffin implements Dessert {
serve(): string {
return "머핀을 제공합니다";
}
}
// 4. 추상 팩토리
interface CafeSetFactory {
createCoffee(): Coffee;
createDessert(): Dessert;
}
// 5. 구체 팩토리들
class AmericanoSetFactory implements CafeSetFactory {
createCoffee(): Coffee {
return new Americano();
}
createDessert(): Dessert {
return new Cookie();
}
}
class LatteSetFactory implements CafeSetFactory {
createCoffee(): Coffee {
return new Latte();
}
createDessert(): Dessert {
return new Muffin();
}
}
// 6. 클라이언트 코드
function orderCafeSet(factory: CafeSetFactory) {
const coffee = factory.createCoffee();
const dessert = factory.createDessert();
console.log(coffee.prepare());
console.log(dessert.serve());
}
// 7. 실행
orderCafeSet(new AmericanoSetFactory());
orderCafeSet(new LatteSetFactory());
위 예제를 실행한다면 다음과 같은 결과를 확인할수있다.

하나하나 구조를 뜯어보면서 이해해 보려고 한다.
(1) 제품군의 추상 인터페이스
interface Coffee {
prepare(): string;
}
interface Dessert {
serve(): string;
}
커피든 디저트든 "어떻게 만들어지는지는 몰라도", 모두 prepare, serve 메서드를 가진다.
(2) 추상 인터페이스의 구현체들
class Americano implements Coffee {
prepare(): string {
return "아메리카노를 준비합니다";
}
}
인터페이스는 실제 동작이 없기 때문에, 현실에서 사용할 수 있는 구현체가 필요하다.
(3) 제품군 생성을 위한 추상 팩토리
interface CafeSetFactory {
createCoffee(): Coffee;
createDessert(): Dessert;
}
어떤 구체적인 커피와 디저트를 만드는지는 몰라도 되고, 커피와 디저트를 바꿔도 코드는 바뀌지 않게된다.
(4) 실제 팩토리
class AmericanoSetFactory implements CafeSetFactory {
createCoffee() {
return new Americano();
}
createDessert() {
return new Cookie();
}
}
스타일 별로 제품군(커피 + 디저트)를 묶어서 생성한다.
이걸로 일관된 조합을 보장할 수 있다.
(5) 클라이언트 코드
function orderCafeSet(factory: CafeSetFactory) {
const coffee = factory.createCoffee();
const dessert = factory.createDessert();
console.log(coffee.prepare());
console.log(dessert.serve());
}
어던 스타일의 세트를 고를지 팩토리만 바꾸면 끝이다.
클라이언트는 new Americano() 나 new Muffin()을 직접 호출할 필요가 없다.
그래서 클라이언트는 어떤 커피를 어떤 디저트를 만들지 직접 결정하지 않고 팩토리를 호출한다.
즉, 팩토리를 통해 일관된 방식으로 세트를 생성할 수 있게된다.
만약 Latte 세트를 시켰는데 커피는 Latte를 시켰는데 디저트가 Muffin이 아니라 Cookie면
이건 그냥 스타일이 뒤섞인거고 추상 팩토리가 없다면 이런 조합이 실수로 생길수 있는거다.
그래서 추상팩토리는 Latte + Muffin, Americano + Cookie 이런 " 쌍 " 을 공장 단위로 책임지게 만들어서
제품군 간 일관성을 보장하는 것이다.
이런 구조를 가진 추상 팩토리 패턴이 없다면 어떤 문제점이 발생할까...?
만약 클라이언트가 new를 직접 사용했다면?
function orderCafeSet(style: string) {
let coffee: Coffee;
let dessert: Dessert;
if (style === "americano") {
coffee = new Americano();
dessert = new Cookie();
} else if (style === "latte") {
coffee = new Latte();
dessert = new Muffin();
} else {
throw new Error("알 수 없는 스타일");
}
console.log(coffee.prepare());
console.log(dessert.serve());
}
- if-else 로 스타일 마다 조건문이 작성되며
- 새로운 스타일이 추가되면 클라이언트 코드가 수정되어야한다.(OCP 위반)
- 테스트, 유지보수, 확장이 어렵다.
하지만 추상 팩토리가 있다면 orderCafeSet(factory: CafeSetFactory) 이 코드 자체는 안바뀌고
CappuccinoSetFactory 만 새로 만들면 끝이다.
위 구조를 UML로 도식화 하면 아래와 같다.

UML을 요약하자면 아래와 같다!
1. 추상 제품 인터페이스 (제품군 정의)
(1) Coffee : 모든 커피 클래스가 따라야 할 인터페이스
-> prepare(): string
(2) Dessert : 모든 디저트 클래스가 따라야 할 인터페이스
-> serve() : string
2. 구체 제품 클래스 (제품군 구현)
(1) Americano, Latte → Coffee를 구현
(2) Cookie, Muffin → Dessert를 구현
3. 추상 팩토리 (제품 세트를 만드는 계약서)
CafeSetFactory:
-> createCoffee(): Coffee
-> createDessert(): Dessert
: 커피와 디저트를 한 세트로 만드는 인터페이스
4. 구체 팩토리 (세트 스타일에 따라 객체 생성)
(1) AmericanoSetFactory:
→ createCoffee() → Americano
→ createDessert() → Cookie
(2) LatteSetFactory:
→ createCoffee() → Latte
→ createDessert() → Muffin
5. 클라이언트 코드
orderCafeSet(factory: CafeSetFactory)
→ 팩토리만 전달받아서
→ createCoffee()와 createDessert()를 호출
→ 커피와 디저트를 일관된 세트로 생성
Reference
https://refactoring.guru/ko/design-patterns/abstract-factory
추상 팩토리 패턴
/ 디자인 패턴들 / 생성 패턴 추상 팩토리 패턴 다음 이름으로도 불립니다: Abstract Factory 의도 추상 팩토리는 관련 객체들의 구상 클래스들을 지정하지 않고도 관련 객체들의 모음을 생성할 수 있
refactoring.guru
https://patterns-dev-kr.github.io/design-patterns/factory-pattern/
Factory 패턴
📜 원문: patterns.dev - factory pattern 팩토리 패턴을 사용하면 함수를 호출하는 것으로 객체를 만들어낼 수 있다. new 키워드를 사용하는 대신 함수 호출의 결과로 객체를 만들 수 있는 것이다. 앱에
patterns-dev-kr.github.io
'공부 > 디자인 패턴' 카테고리의 다른 글
| [디자인 패턴] MVC 와 MVVM 패턴 이해하기 (0) | 2026.01.29 |
|---|---|
| 디자인패턴 - 팩토리 메서드 패턴 (2) | 2025.07.08 |
| 디자인 패턴 - 싱글톤 (0) | 2025.06.27 |