diff --git "a/changyu/03.\353\215\260\354\275\224\353\240\210\354\235\264\355\204\260_\355\214\250\355\204\264.md" "b/changyu/03.\353\215\260\354\275\224\353\240\210\354\235\264\355\204\260_\355\214\250\355\204\264.md"
new file mode 100644
index 0000000..69a151c
--- /dev/null
+++ "b/changyu/03.\353\215\260\354\275\224\353\240\210\354\235\264\355\204\260_\355\214\250\355\204\264.md"
@@ -0,0 +1,433 @@
+# Week 3. 데코레이터(Decorator) 패턴
+
+## 학습 정보
+
+- **주차**: 3주차
+- **챕터**: Chapter 03 — 객체 꾸미기
+- **패턴명**: 데코레이터 패턴 (Decorator Pattern)
+- **학습일**: 2025-03-03
+- **학습 범위**: Chapter 03 전체
+
+---
+
+## 학습 목표
+
+- 상속을 남용했을 때 발생하는 클래스 폭발 문제를 이해하고, 구성(Composition)으로 해결하는 방법을 학습한다.
+- 데코레이터 패턴의 구조와 동작 원리를 파악하고, TypeScript로 직접 구현한다.
+- OCP(개방-폐쇄 원칙)의 의미를 이해하고, 데코레이터 패턴이 이 원칙을 어떻게 실현하는지 파악한다.
+
+---
+
+## 핵심 개념
+
+### 패턴이 해결하는 문제
+
+스타버즈 커피 주문 시스템을 예로 들어보자.
+
+기본 음료(에스프레소, 하우스 블렌드 등)에 첨가물(우유, 모카, 휘핑크림 등)을 조합해야 하는 상황이다.
+
+**해결 시도 1: 조합마다 서브클래스 생성**
+
+모든 조합에 대해 클래스를 만드는 방식이다. `HouseBlendWithMocha`, `HouseBlendWithMochaAndWhip` 같은 클래스가 기하급수적으로 늘어나는 "클래스 폭발" 문제가 발생한다.
+
+첨가물 가격이 바뀌거나 새로운 첨가물이 추가되면 수많은 클래스를 전부 수정해야 한다.
+
+**해결 시도 2: 슈퍼클래스에 불리언 플래그 추가**
+
+`Beverage` 클래스에 `hasMilk`, `hasSoy`, `hasMocha`, `hasWhip` 같은 불리언 변수를 두고, `cost()`에서 플래그를 확인하여 가격을 계산하는 방식이다.
+
+클래스 수는 줄어들지만 다음과 같은 문제가 남는다.
+
+- 첨가물 종류가 추가될 때마다 슈퍼클래스의 코드를 수정해야 한다.
+- 특정 음료에 어울리지 않는 첨가물(예: 아이스티에 휘핑크림)도 상속받게 된다.
+- 더블 모카처럼 같은 첨가물을 두 번 추가하는 경우를 처리할 수 없다.
+
+두 시도 모두 "바뀌는 부분을 캡슐화한다"와 "클래스는 확장에 열려 있고 변경에 닫혀 있어야 한다(OCP)"를 지키지 못하고 있다.
+
+데코레이터 패턴은 이 문제를 객체를 동적으로 감싸는(wrapping) 방식으로 해결한다.
+
+### 패턴의 정의
+
+> **데코레이터 패턴(Decorator Pattern)** 으로 객체에 추가 요소를 동적으로 더할 수 있다.
+>
+> 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있다.
+
+핵심 아이디어는 다음과 같다.
+
+기본 객체를 데코레이터 객체로 감싸고, 데코레이터는 자신이 감싼 객체에게 작업을 위임한 뒤 추가 행동을 덧붙인다.
+
+데코레이터는 감싸는 객체와 같은 슈퍼타입을 가지므로, 원래 객체가 들어갈 자리에 데코레이터를 넣어도 문제가 없다.
+
+### 주요 구성요소
+
+- **Component (Beverage)**
+
+ 구성 요소의 공통 인터페이스 또는 추상 클래스.
+
+ 구상 구성 요소와 데코레이터 모두 이 타입을 공유한다.
+- **ConcreteComponent (Espresso, HouseBlend 등)**
+
+ 기본 행동을 구현하는 구상 클래스.
+
+ 데코레이터로 감싸져 새로운 행동이 추가되는 대상이다.
+- **Decorator (CondimentDecorator)**
+
+ Component를 확장하는 추상 클래스.
+
+ 내부에 Component 참조를 가지며, 이를 통해 감싸는 객체에 작업을 위임한다.
+- **ConcreteDecorator (Mocha, Whip, Soy 등)**
+
+ Decorator를 구현한 구상 클래스.
+
+ 위임 결과에 자신만의 행동을 추가한다.
+
+---
+
+## 패턴 구조
+
+### UML 다이어그램
+
+```mermaid
+classDiagram
+ direction TB
+
+ class Beverage {
+ <>
+ #description string
+ +getDescription() string
+ +cost() number*
+ }
+
+ class CondimentDecorator {
+ <>
+ #beverage Beverage
+ +getDescription() string*
+ }
+
+ class Espresso {
+ +cost() number
+ }
+
+ class HouseBlend {
+ +cost() number
+ }
+
+ class DarkRoast {
+ +cost() number
+ }
+
+ class Decaf {
+ +cost() number
+ }
+
+ class Mocha {
+ +cost() number
+ +getDescription() string
+ }
+
+ class Whip {
+ +cost() number
+ +getDescription() string
+ }
+
+ class Soy {
+ +cost() number
+ +getDescription() string
+ }
+
+ class Milk {
+ +cost() number
+ +getDescription() string
+ }
+
+ Beverage <|-- Espresso
+ Beverage <|-- HouseBlend
+ Beverage <|-- DarkRoast
+ Beverage <|-- Decaf
+ Beverage <|-- CondimentDecorator
+
+ CondimentDecorator <|-- Mocha
+ CondimentDecorator <|-- Whip
+ CondimentDecorator <|-- Soy
+ CondimentDecorator <|-- Milk
+
+ CondimentDecorator --> Beverage : wraps
+```
+
+여기서 상속은 **행동을 물려받기 위한 것이 아니라 타입을 맞추기 위한 것**이다.
+
+`CondimentDecorator`가 `Beverage`를 상속하는 이유는 데코레이터가 원래 구성 요소와 같은 자리에 들어갈 수 있어야 하기 때문이다.
+
+실제 행동의 확장은 구성(Composition)과 위임(Delegation)을 통해 이루어진다.
+
+### 동작 방식
+
+모카와 휘핑크림을 추가한 다크 로스트 커피의 가격 계산 과정을 예로 들어보자.
+
+1. `DarkRoast` 객체를 생성한다.
+2. `Mocha` 데코레이터로 `DarkRoast`를 감싼다.
+3. `Whip` 데코레이터로 `Mocha`를 감싼다.
+4. 가장 바깥쪽 `Whip`의 `cost()`를 호출한다.
+5. `Whip`은 내부의 `Mocha`에게 `cost()`를 위임한다.
+6. `Mocha`는 내부의 `DarkRoast`에게 `cost()`를 위임한다.
+7. `DarkRoast`가 0.99를 반환한다.
+8. `Mocha`가 0.99 + 0.20 = 1.19를 반환한다.
+9. `Whip`이 1.19 + 0.10 = 1.29를 반환한다.
+
+각 데코레이터는 감싸고 있는 객체에 작업을 위임한 뒤, 그 결과에 자신의 비용을 더하는 방식으로 동작한다.
+
+데코레이터를 여러 겹 감싸도 이 위임 체인이 자연스럽게 연결된다.
+
+---
+
+## 코드 예제
+
+### 예제 상황
+
+스타버즈 커피 주문 시스템이다.
+
+기본 음료(에스프레소, 하우스 블렌드, 다크 로스트, 디카페인)에 첨가물(모카, 두유, 휘핑크림 등)을 자유롭게 조합할 수 있어야 한다.
+
+같은 첨가물을 여러 번 추가하는 것(더블 모카 등)도 가능해야 하며, 기존 코드를 수정하지 않고 새로운 첨가물을 추가할 수 있는 확장성이 요구된다.
+
+### 추상 클래스 정의
+
+```typescript
+/** Component — 음료의 추상 클래스 */
+export abstract class Beverage {
+ protected description: string = "제목 없음";
+
+ public getDescription() {
+ return this.description;
+ }
+
+ public abstract cost(): number;
+}
+
+/** Decorator — 첨가물 데코레이터의 추상 클래스 */
+export abstract class CondimentDecorator extends Beverage {
+ // 감싸는 대상을 Beverage 타입으로 저장한다.
+ // 어떤 음료든, 어떤 데코레이터든 감쌀 수 있다.
+ constructor(protected beverage: Beverage) {
+ super();
+ }
+
+ public abstract getDescription(): string;
+}
+```
+
+### 구상 구성 요소: 기본 음료
+
+```typescript
+export class Espresso extends Beverage {
+ constructor() {
+ super();
+ this.description = "에스프레소";
+ }
+
+ public cost() {
+ return 1.99;
+ }
+}
+
+export class HouseBlend extends Beverage {
+ constructor() {
+ super();
+ this.description = "하우스 블렌드 커피";
+ }
+
+ public cost() {
+ return 0.89;
+ }
+}
+
+export class DarkRoast extends Beverage {
+ constructor() {
+ super();
+ this.description = "다크 로스트 커피";
+ }
+
+ public cost() {
+ return 0.99;
+ }
+}
+
+export class Decaf extends Beverage {
+ constructor() {
+ super();
+ this.description = "디카페인 커피";
+ }
+
+ public cost() {
+ return 1.05;
+ }
+}
+```
+
+### 구상 데코레이터: 첨가물
+
+```typescript
+export class Mocha extends CondimentDecorator {
+ constructor(beverage: Beverage) {
+ super(beverage);
+ }
+
+ public getDescription() {
+ return this.beverage.getDescription() + ", 모카";
+ }
+
+ public cost() {
+ return this.beverage.cost() + 0.2;
+ }
+}
+
+export class Soy extends CondimentDecorator {
+ constructor(beverage: Beverage) {
+ super(beverage);
+ }
+
+ public getDescription() {
+ return this.beverage.getDescription() + ", 두유";
+ }
+
+ public cost() {
+ return this.beverage.cost() + 0.15;
+ }
+}
+
+export class Whip extends CondimentDecorator {
+ constructor(beverage: Beverage) {
+ super(beverage);
+ }
+
+ public getDescription() {
+ return this.beverage.getDescription() + ", 휘핑크림";
+ }
+
+ public cost() {
+ return this.beverage.cost() + 0.1;
+ }
+}
+```
+
+### 실행 코드
+
+```typescript
+// 1. 아무것도 넣지 않은 에스프레소
+const beverage1 = new Espresso();
+console.log(`${beverage1.getDescription()} $${beverage1.cost()}`);
+// 에스프레소 $1.99
+
+// 2. 더블 모카 + 휘핑크림 다크 로스트
+let beverage2 = new DarkRoast();
+beverage2 = new Mocha(beverage2); // 모카 추가
+beverage2 = new Mocha(beverage2); // 모카 한 번 더 추가
+beverage2 = new Whip(beverage2); // 휘핑크림 추가
+console.log(`${beverage2.getDescription()} $${beverage2.cost()}`);
+// 다크 로스트 커피, 모카, 모카, 휘핑크림 $1.49
+
+// 3. 두유 + 모카 + 휘핑크림 하우스 블렌드
+let beverage3 = new HouseBlend();
+beverage3 = new Soy(beverage3);
+beverage3 = new Mocha(beverage3);
+beverage3 = new Whip(beverage3);
+console.log(`${beverage3.getDescription()} $${beverage3.cost()}`);
+// 하우스 블렌드 커피, 두유, 모카, 휘핑크림 $1.34
+```
+
+### 코드 설명
+
+- **타입 일치를 위한 상속**
+
+ `CondimentDecorator`는 `Beverage`를 상속하지만, 이는 행동을 물려받기 위함이 아니다.
+
+ 데코레이터가 원래 `Beverage` 자리에 들어갈 수 있도록 타입을 맞추는 것이 목적이다.
+- **구성을 통한 행동 확장**
+
+ 실제 행동 확장은 `beverage` 인스턴스 변수(구성)와 위임으로 이루어진다.
+
+ `cost()` 호출 시 감싸고 있는 객체에 먼저 위임한 뒤, 그 결과에 자신의 비용을 더한다.
+- **무제한 중첩**
+
+ 데코레이터가 `Beverage`와 같은 타입이므로 여러 겹으로 감쌀 수 있다.
+
+ 더블 모카처럼 같은 데코레이터를 두 번 적용하는 것도 자연스럽게 처리된다.
+- **기존 코드 무변경 확장**
+ 새로운 첨가물(예: `Milk`)을 추가할 때 기존 클래스를 전혀 수정하지 않고 `CondimentDecorator`를 상속한 새 클래스만 만들면 된다.
+
+---
+
+## 구현 방식 비교
+
+데코레이터 패턴을 도입하기까지 검토한 세 가지 접근법을 비교한다.
+
+| 구분 | 조합별 서브클래스 | 슈퍼클래스 플래그 | 데코레이터 패턴 |
+| ----------- | -------------------------------------------- | -------------------------------------- | ------------------------------------- |
+| 방식 | 음료+첨가물 조합마다 클래스 생성 | Beverage에 불리언 플래그와 조건문 추가 | 기본 객체를 데코레이터로 동적 감싸기 |
+| 클래스 수 | 조합이 늘어날수록 기하급수적 증가 | 적음 (음료 종류만큼) | 적당함 (음료 + 첨가물 각각) |
+| 확장성 | 새 첨가물 추가 시 모든 조합 클래스 추가 필요 | 슈퍼클래스 코드 수정 필요 | 새 데코레이터 클래스만 추가하면 됨 |
+| 동적 조합 | 불가능 (컴파일 시 결정) | 부분적 가능 (플래그 변경) | 완전 가능 (런타임 조합) |
+| OCP 준수 | 위반 | 위반 | 준수 |
+| 적합한 상황 | 사용하지 않는 것이 좋다 | 조합이 극히 단순하고 변경이 없을 때 | 조합이 다양하고 동적 확장이 필요할 때 |
+
+---
+
+## 실전 활용
+
+### 언제 사용하면 좋을까?
+
+- 기존 객체의 코드를 변경하지 않고 런타임에 기능을 추가하거나 제거해야 할 때
+- 서브클래스로 확장하면 조합이 폭발적으로 늘어나는 구조일 때
+- 여러 기능을 자유롭게 조합해야 하고, 같은 기능을 중복 적용할 수도 있을 때
+
+### 장단점
+
+**장점**
+
+- OCP를 준수한다. 기존 코드를 수정하지 않고 새로운 행동을 추가할 수 있다.
+- 상속으로 인한 클래스 폭발 문제를 해결한다.
+- 런타임에 데코레이터를 자유롭게 조합하여 행동을 동적으로 확장할 수 있다.
+- 같은 데코레이터를 여러 번 적용하는 것(더블 모카 등)도 자연스럽게 처리된다.
+
+**단점**
+
+- 자잘한 객체가 많이 생겨 코드가 복잡해질 수 있다.
+- 데코레이터를 여러 겹 감싼 구조에서 디버깅이 어려울 수 있다.
+- 구상 구성 요소의 구체적인 타입에 의존하는 코드에서는 데코레이터 패턴이 제대로 동작하지 않는다. 추상 타입(Component)에 의존하는 코드에서만 올바르게 작동한다.
+- 데코레이터 객체의 생성과 조합을 관리하는 별도의 로직(팩토리, 빌더 등)이 필요할 수 있다.
+
+### 실제 적용 사례
+
+- **TypeScript/JavaScript 데코레이터**: `@log`, `@validate` 같은 데코레이터 문법으로 클래스나 메서드에 횡단 관심사를 추가한다. 문법은 다르지만 "기존 코드를 수정하지 않고 행동을 추가한다"는 핵심 원리는 동일하다.
+- **Express/Koa 미들웨어**: 요청 처리 파이프라인에 미들웨어를 순서대로 추가하는 구조가 데코레이터 패턴의 변형이다. 각 미들웨어는 다음 미들웨어에 처리를 위임하기 전후에 자신의 로직을 수행한다.
+- **React 고차 컴포넌트(HOC)**: `withAuth(Component)`, `withTheme(Component)` 처럼 컴포넌트를 감싸서 추가 기능을 부여하는 패턴이다.
+
+---
+
+## 핵심 정리
+
+- 데코레이터 패턴은 객체를 동적으로 감싸서 기존 코드를 수정하지 않고 새로운 행동을 추가하는 패턴이다.
+- 상속은 타입을 맞추는 용도로만 사용하고, 실제 행동 확장은 구성과 위임으로 이루어진다. 이 점이 단순한 상속과 데코레이터 패턴의 핵심적인 차이다.
+- 데코레이터와 구성 요소는 같은 슈퍼타입을 공유하므로 원래 객체 자리에 데코레이터를 넣을 수 있고, 여러 겹으로 중첩할 수 있다.
+- OCP(개방-폐쇄 원칙)를 준수하는 대표적인 패턴이지만, 자잘한 객체가 많아질 수 있으므로 팩토리나 빌더 패턴과 함께 사용하는 것이 일반적이다.
+
+---
+
+## 함께 등장한 디자인 원칙
+
+| 원칙 | 이 패턴에서의 적용 |
+| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
+| 바뀌는 부분은 캡슐화한다 | 첨가물(변하는 부분)을 데코레이터 클래스로 캡슐화하여 기본 음료 클래스와 분리 |
+| 상속보다는 구성을 활용한다 | 상속은 타입 일치 용도로만 사용하고, 행동 확장은 데코레이터 내부의 Component 참조(구성)로 처리 |
+| 구현보다는 인터페이스에 맞춰서 프로그래밍한다 | 데코레이터와 구성 요소 모두 Beverage(추상 타입)에 의존하여 구체 클래스를 알 필요 없이 동작 |
+| 상호작용하는 객체 사이에서는 느슨한 결합을 사용한다 | 데코레이터는 감싸는 객체의 구체 타입을 모르고 Beverage 인터페이스만으로 상호작용 |
+| **클래스는 확장에 열려 있고 변경에 닫혀 있어야 한다 (OCP)** | 새로운 첨가물 추가 시 기존 Beverage나 다른 데코레이터 코드를 전혀 수정하지 않고 새 데코레이터 클래스만 추가 |
+
+---
+
+## 관련 패턴
+
+- **전략 패턴 (Strategy)**: 전략 패턴은 알고리즘 전체를 교체하고, 데코레이터 패턴은 기존 행동에 새로운 행동을 겹겹이 추가한다. 전략은 "대체", 데코레이터는 "추가"에 초점이 있다.
+- **팩토리 패턴 / 빌더 패턴**: 데코레이터 객체의 생성과 조합이 복잡해지면 팩토리나 빌더 패턴으로 객체 생성을 캡슐화한다. 데코레이터 패턴의 실무 적용에서 흔히 함께 사용된다.
+- **어댑터 패턴 (Adapter)**: 어댑터는 인터페이스를 변환하고, 데코레이터는 인터페이스를 유지하면서 행동을 추가한다. 두 패턴 모두 래퍼(Wrapper) 구조를 사용하지만 목적이 다르다.
+- **프록시 패턴 (Proxy)**: 프록시는 접근을 제어하고, 데코레이터는 기능을 추가한다. 구조적으로는 유사하지만 의도가 다르다.
diff --git "a/changyu/04.\355\214\251\355\206\240\353\246\254_\355\214\250\355\204\264.md" "b/changyu/04.\355\214\251\355\206\240\353\246\254_\355\214\250\355\204\264.md"
new file mode 100644
index 0000000..741cdff
--- /dev/null
+++ "b/changyu/04.\355\214\251\355\206\240\353\246\254_\355\214\250\355\204\264.md"
@@ -0,0 +1,728 @@
+# Week 4. 팩토리(Factory) 패턴
+
+## 학습 정보
+
+- **주차**: 4주차
+- **챕터**: Chapter 04 — 객체지향 빵 굽기
+- **패턴명**: 팩토리 패턴 (간단한 팩토리 / 팩토리 메소드 / 추상 팩토리)
+- **학습일**: 2025-03-10
+- **학습 범위**: Chapter 04 전체
+
+---
+
+## 학습 목표
+
+- `new` 연산자의 남용이 초래하는 결합 문제를 이해하고, 객체 생성을 캡슐화하는 필요성을 파악한다.
+- 간단한 팩토리, 팩토리 메소드 패턴, 추상 팩토리 패턴의 차이를 명확히 구분한다.
+- 의존성 뒤집기 원칙(DIP)을 이해하고, 팩토리 패턴이 이 원칙을 어떻게 실현하는지 파악한다.
+
+---
+
+## 핵심 개념
+
+### 패턴이 해결하는 문제
+
+`new`를 사용하면 반드시 구상 클래스의 인스턴스가 만들어진다. 인터페이스에 맞춰 프로그래밍하라고 배웠지만, 결국 어딘가에서는 구상 클래스를 지정해야 한다.
+
+```typescript
+let pizza: Pizza;
+
+if (type === "cheese") {
+ pizza = new CheesePizza();
+} else if (type === "pepperoni") {
+ pizza = new PepperoniPizza();
+} else if (type === "clam") {
+ pizza = new ClamPizza();
+}
+```
+
+이런 코드의 문제점은 다음과 같다.
+
+- 피자 종류가 추가되거나 제거될 때마다 이 조건문을 직접 수정해야 한다.
+- 동일한 생성 로직이 여러 곳에 흩어져 있으면 변경 시 모든 곳을 찾아 고쳐야 한다.
+- 구상 클래스에 직접 의존하므로 변경에 닫혀 있지 않다.
+
+`new` 자체가 문제가 아니라, **변화하는 부분(어떤 구상 클래스를 생성할지)이 캡슐화되지 않은 것**이 문제다.
+
+팩토리 패턴은 객체 생성 코드를 분리하여 이 문제를 해결한다.
+
+### 패턴의 정의
+
+이 챕터에서는 세 가지 팩토리 관련 개념을 다룬다.
+
+> **Simple Factory**
+>
+> 객체 생성을 처리하는 별도의 클래스를 만드는 프로그래밍 관용구다.
+>
+> 엄밀히 말해 디자인 패턴은 아니지만, 자주 사용되는 기법이다.
+
+> **Factory Method Pattern**
+>
+> 객체를 생성할 때 필요한 인터페이스를 만든다.
+>
+> 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정한다.
+>
+> 인스턴스 만드는 일을 서브클래스에 맡기는 패턴이다.
+
+> **Abstract Factory Pattern**
+>
+> 구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공한다.
+>
+> 구상 클래스는 서브클래스에서 만든다.
+
+### 주요 구성요소
+
+**팩토리 메소드 패턴의 구성요소**
+
+- **Creator (PizzaStore)**: 팩토리 메소드를 선언하는 추상 클래스. 제품을 사용하는 코드(orderPizza 등)를 포함한다.
+- **ConcreteCreator (NYPizzaStore, ChicagoPizzaStore)**: 팩토리 메소드를 구현하여 실제 제품 인스턴스를 생성하는 서브클래스다.
+- **Product (Pizza)**: 팩토리 메소드가 생성하는 제품의 추상 타입이다.
+- **ConcreteProduct (NYStyleCheesePizza 등)**: 실제로 만들어지는 구상 제품 클래스다.
+
+**추상 팩토리 패턴의 구성요소**
+
+- **AbstractFactory (PizzaIngredientFactory)**: 제품군 전체를 생산하는 메소드를 정의하는 인터페이스다.
+- **ConcreteFactory (NYPizzaIngredientFactory 등)**: 특정 지역/환경에 맞는 제품군을 실제로 생산하는 구상 팩토리다.
+- **AbstractProduct (Dough, Sauce, Cheese 등)**: 제품군을 구성하는 각 제품의 추상 타입이다.
+- **ConcreteProduct (ThinCrustDough, MarinaraSauce 등)**: 각 제품의 구상 구현이다.
+
+---
+
+## 패턴 구조
+
+### UML 다이어그램 — 팩토리 메소드 패턴
+
+```mermaid
+classDiagram
+ direction TB
+
+ class PizzaStore {
+ <>
+ +orderPizza(type: string) Pizza
+ #createPizza(type: string) Pizza*
+ }
+
+ class NYPizzaStore {
+ #createPizza(type: string) Pizza
+ }
+
+ class ChicagoPizzaStore {
+ #createPizza(type: string) Pizza
+ }
+
+ class Pizza {
+ <>
+ +prepare() void
+ +bake() void
+ +cut() void
+ +box() void
+ }
+
+ class NYStyleCheesePizza
+ class ChicagoStyleCheesePizza
+
+ PizzaStore <|-- NYPizzaStore
+ PizzaStore <|-- ChicagoPizzaStore
+ PizzaStore --> Pizza : uses
+
+ Pizza <|-- NYStyleCheesePizza
+ Pizza <|-- ChicagoStyleCheesePizza
+
+ NYPizzaStore ..> NYStyleCheesePizza : creates
+ ChicagoPizzaStore ..> ChicagoStyleCheesePizza : creates
+```
+
+### UML 다이어그램 — 추상 팩토리 패턴
+
+```mermaid
+classDiagram
+ direction TB
+
+ class PizzaIngredientFactory {
+ <>
+ +createDough() Dough
+ +createSauce() Sauce
+ +createCheese() Cheese
+ +createClam() Clams
+ }
+
+ class NYPizzaIngredientFactory {
+ +createDough() Dough
+ +createSauce() Sauce
+ +createCheese() Cheese
+ +createClam() Clams
+ }
+
+ class ChicagoPizzaIngredientFactory {
+ +createDough() Dough
+ +createSauce() Sauce
+ +createCheese() Cheese
+ +createClam() Clams
+ }
+
+ class Dough { <> }
+ class Sauce { <> }
+ class Cheese { <> }
+ class Clams { <> }
+
+ class ThinCrustDough
+ class ThickCrustDough
+ class MarinaraSauce
+ class PlumTomatoSauce
+
+ PizzaIngredientFactory <|.. NYPizzaIngredientFactory
+ PizzaIngredientFactory <|.. ChicagoPizzaIngredientFactory
+
+ Dough <|.. ThinCrustDough
+ Dough <|.. ThickCrustDough
+ Sauce <|.. MarinaraSauce
+ Sauce <|.. PlumTomatoSauce
+
+ NYPizzaIngredientFactory ..> ThinCrustDough : creates
+ NYPizzaIngredientFactory ..> MarinaraSauce : creates
+ ChicagoPizzaIngredientFactory ..> ThickCrustDough : creates
+ ChicagoPizzaIngredientFactory ..> PlumTomatoSauce : creates
+```
+
+### 동작 방식 — 팩토리 메소드 패턴
+
+1. 클라이언트가 `NYPizzaStore` 인스턴스를 생성한다.
+2. `orderPizza("cheese")`를 호출한다. 이 메소드는 추상 클래스 `PizzaStore`에 정의되어 있다.
+3. `orderPizza()` 내부에서 `createPizza("cheese")`를 호출한다. 이 메소드는 추상 메소드이므로 서브클래스인 `NYPizzaStore`의 구현이 실행된다.
+4. `NYPizzaStore.createPizza()`가 `NYStyleCheesePizza` 인스턴스를 생성하여 반환한다.
+5. `orderPizza()`는 반환받은 피자에 대해 `prepare()`, `bake()`, `cut()`, `box()`를 순서대로 호출한다. 어떤 구상 피자인지는 알지 못한다.
+
+### 동작 방식 — 추상 팩토리 패턴
+
+1. `NYPizzaStore`의 `createPizza()`에서 `NYPizzaIngredientFactory`를 생성한다.
+2. 이 원재료 팩토리를 `CheesePizza` 생성자에 전달한다.
+3. `CheesePizza.prepare()`가 호출되면, 팩토리의 `createDough()`, `createSauce()`, `createCheese()` 등을 호출하여 지역에 맞는 원재료를 받아온다.
+4. 피자 클래스는 어떤 구상 원재료가 사용되는지 전혀 알지 못한다. 팩토리 인터페이스에만 의존한다.
+
+---
+
+## 코드 예제
+
+### 예제 상황
+
+피자 가게 프랜차이즈 시스템이다.
+
+본사(`PizzaStore`)에서 정한 주문 프로세스(준비 → 굽기 → 자르기 → 포장)는 모든 지점이 동일하게 따라야 한다.
+
+하지만 피자 스타일(뉴욕: 얇은 빵 + 마리나라 소스 / 시카고: 두꺼운 빵 + 플럼토마토 소스)은 지점마다 다르다.
+
+나아가 각 지점이 사용하는 원재료(반죽, 소스, 치즈 등)의 품질을 본사에서 관리할 수 있어야 한다.
+
+### 1단계: 간단한 팩토리
+
+가장 기본적인 형태로, 객체 생성 코드를 별도 클래스로 분리한다.
+
+```typescript
+// --- 제품 ---
+abstract class Pizza {
+ public name = "";
+ public dough = "";
+ public sauce = "";
+ public toppings: string[] = [];
+
+ public prepare() {
+ console.log(`준비 중: ${this.name}`);
+ console.log("도우를 돌리는 중...");
+ console.log("소스를 뿌리는 중...");
+ console.log("토핑을 올리는 중:");
+ this.toppings.forEach((t) => console.log(` ${t}`));
+ }
+
+ public bake() {
+ console.log("175도에서 25분 간 굽기");
+ }
+
+ public cut() {
+ console.log("피자를 사선으로 자르기");
+ }
+
+ public box() {
+ console.log("상자에 피자 담기");
+ }
+}
+
+class CheesePizza extends Pizza {
+ constructor() {
+ super();
+ this.name = "치즈 피자";
+ this.toppings.push("모짜렐라 치즈");
+ }
+}
+
+class PepperoniPizza extends Pizza {
+ constructor() {
+ super();
+ this.name = "페퍼로니 피자";
+ this.toppings.push("페퍼로니");
+ }
+}
+
+// --- 간단한 팩토리 ---
+class SimplePizzaFactory {
+ public createPizza(type: string) {
+ switch (type) {
+ case "cheese":
+ return new CheesePizza();
+ case "pepperoni":
+ return new PepperoniPizza();
+ default:
+ return null;
+ }
+ }
+}
+
+// --- 클라이언트 ---
+class PizzaStore {
+ constructor(private factory: SimplePizzaFactory) {}
+
+ public orderPizza(type: string) {
+ const pizza = this.factory.createPizza(type);
+ if (!pizza) return null;
+
+ pizza.prepare();
+ pizza.bake();
+ pizza.cut();
+ pizza.box();
+
+ return pizza;
+ }
+}
+```
+
+간단한 팩토리는 디자인 패턴이 아니라 **관용구**에 가깝다.
+
+객체 생성을 한 곳으로 모아 관리할 수 있지만, 제품 변경 시 팩토리 코드를 직접 수정해야 하므로 유연성에 한계가 있다.
+
+### 2단계: 팩토리 메소드 패턴
+
+지점마다 다른 스타일의 피자를 만들어야 하는 상황이다. 객체 생성을 서브클래스에 맡긴다.
+
+```typescript
+// --- 제품 ---
+abstract class Pizza {
+ public name = "";
+ public dough = "";
+ public sauce = "";
+ public toppings: string[] = [];
+
+ public prepare() {
+ console.log(`준비 중: ${this.name}`);
+ console.log("도우를 돌리는 중...");
+ console.log("소스를 뿌리는 중...");
+ console.log("토핑을 올리는 중:");
+ this.toppings.forEach((t) => console.log(` ${t}`));
+ }
+
+ public bake() {
+ console.log("175도에서 25분 간 굽기");
+ }
+
+ public cut() {
+ console.log("피자를 사선으로 자르기");
+ }
+
+ public box() {
+ console.log("상자에 피자 담기");
+ }
+}
+
+class NYStyleCheesePizza extends Pizza {
+ constructor() {
+ super();
+ this.name = "뉴욕 스타일 소스와 치즈 피자";
+ this.dough = "씬 크러스트 도우";
+ this.sauce = "마리나라 소스";
+ this.toppings.push("잘게 썬 레지아노 치즈");
+ }
+}
+
+class ChicagoStyleCheesePizza extends Pizza {
+ constructor() {
+ super();
+ this.name = "시카고 스타일 딥 디쉬 치즈 피자";
+ this.dough = "아주 두꺼운 크러스트 도우";
+ this.sauce = "플럼토마토 소스";
+ this.toppings.push("잘게 조각낸 모짜렐라 치즈");
+ }
+
+ public cut() {
+ console.log("네모난 모양으로 피자 자르기");
+ }
+}
+
+// --- 생산자 (Creator) ---
+abstract class PizzaStore {
+ // 템플릿 메소드: 주문 프로세스는 고정
+ public orderPizza(type: string) {
+ const pizza = this.createPizza(type);
+ if (!pizza) return null;
+
+ pizza.prepare();
+ pizza.bake();
+ pizza.cut();
+ pizza.box();
+
+ return pizza;
+ }
+
+ // 팩토리 메소드: 어떤 피자를 만들지는 서브클래스가 결정
+ protected abstract createPizza(type: string): Pizza | null;
+}
+
+class NYPizzaStore extends PizzaStore {
+ protected createPizza(type: string) {
+ switch (type) {
+ case "cheese":
+ return new CheesePizza();
+ // ... 다른 뉴욕 스타일 피자들
+ default:
+ return null;
+ }
+ }
+}
+
+class ChicagoPizzaStore extends PizzaStore {
+ protected createPizza(type: string) {
+ switch (type) {
+ case "cheese":
+ return new ChicagoStyleCheesePizza();
+ // ... 다른 시카고 스타일 피자들
+ default:
+ return null;
+ }
+ }
+}
+
+// --- 사용 ---
+const nyStore = new NYPizzaStore();
+const chicagoStore = new ChicagoPizzaStore();
+
+nyStore.orderPizza("cheese");
+chicagoStore.orderPizza("cheese");
+```
+
+핵심은 `orderPizza()`가 `createPizza()`를 호출하지만, 어떤 구상 피자가 만들어지는지 전혀 알지 못한다는 점이다.
+
+서브클래스가 `createPizza()`를 구현함으로써 "어떤 클래스의 인스턴스를 만들지"를 결정한다.
+
+### 3단계: 추상 팩토리 패턴
+
+지점에서 싸구려 원재료를 사용하는 문제가 발생했다.
+
+원재료군 전체를 팩토리로 관리하여 품질을 보장한다.
+
+```typescript
+// --- 원재료 인터페이스 ---
+interface Dough {
+ toString(): string;
+}
+
+interface Sauce {
+ toString(): string;
+}
+
+interface Cheese {
+ toString(): string;
+}
+
+interface Clams {
+ toString(): string;
+}
+
+// --- 뉴욕 원재료 ---
+class ThinCrustDough implements Dough {
+ public toString() {
+ return "씬 크러스트 도우";
+ }
+}
+
+class MarinaraSauce implements Sauce {
+ public toString() {
+ return "마리나라 소스";
+ }
+}
+
+class ReggianoCheese implements Cheese {
+ public toString() {
+ return "레지아노 치즈";
+ }
+}
+
+class FreshClams implements Clams {
+ public toString() {
+ return "신선한 조개";
+ }
+}
+
+// --- 시카고 원재료 ---
+class ThickCrustDough implements Dough {
+ public toString() {
+ return "아주 두꺼운 크러스트 도우";
+ }
+}
+
+class PlumTomatoSauce implements Sauce {
+ public toString() {
+ return "플럼토마토 소스";
+ }
+}
+
+class MozzarellaCheese implements Cheese {
+ public toString() {
+ return "모짜렐라 치즈";
+ }
+}
+
+class FrozenClams implements Clams {
+ public toString() {
+ return "냉동 조개";
+ }
+}
+
+// --- 추상 팩토리 ---
+interface PizzaIngredientFactory {
+ createDough(): Dough;
+ createSauce(): Sauce;
+ createCheese(): Cheese;
+ createClam(): Clams;
+}
+
+class NYPizzaIngredientFactory implements PizzaIngredientFactory {
+ public createDough() {
+ return new ThinCrustDough();
+ }
+
+ public createSauce() {
+ return new MarinaraSauce();
+ }
+
+ public createCheese() {
+ return new ReggianoCheese();
+ }
+
+ public createClam() {
+ return new FreshClams();
+ }
+}
+
+class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
+ public createDough() {
+ return new ThickCrustDough();
+ }
+
+ public createSauce() {
+ return new PlumTomatoSauce();
+ }
+
+ public createCheese() {
+ return new MozzarellaCheese();
+ }
+
+ public createClam() {
+ return new FrozenClams();
+ }
+}
+
+// --- 피자 (원재료 팩토리를 사용) ---
+abstract class Pizza {
+ public name = "";
+ public dough!: Dough;
+ public sauce!: Sauce;
+ public cheese!: Cheese;
+
+ public abstract prepare(): void;
+
+ public bake() {
+ console.log("175도에서 25분 간 굽기");
+ }
+
+ public cut() {
+ console.log("피자를 사선으로 자르기");
+ }
+
+ public box() {
+ console.log("상자에 피자 담기");
+ }
+}
+
+class CheesePizza extends Pizza {
+ constructor(private ingredientFactory: PizzaIngredientFactory) {
+ super();
+ }
+
+ public prepare() {
+ console.log(`준비 중: ${this.name}`);
+ this.dough = this.ingredientFactory.createDough();
+ this.sauce = this.ingredientFactory.createSauce();
+ this.cheese = this.ingredientFactory.createCheese();
+ }
+}
+
+class ClamPizza extends Pizza {
+ public clam!: Clams;
+
+ constructor(private ingredientFactory: PizzaIngredientFactory) {
+ super();
+ }
+
+ public prepare() {
+ console.log(`준비 중: ${this.name}`);
+ this.dough = this.ingredientFactory.createDough();
+ this.sauce = this.ingredientFactory.createSauce();
+ this.cheese = this.ingredientFactory.createCheese();
+ this.clam = this.ingredientFactory.createClam();
+ }
+}
+
+// --- 팩토리 메소드 + 추상 팩토리 결합 ---
+abstract class PizzaStore {
+ public orderPizza(type: string) {
+ const pizza = this.createPizza(type);
+ if (!pizza) return null;
+
+ pizza.prepare();
+ pizza.bake();
+ pizza.cut();
+ pizza.box();
+
+ return pizza;
+ }
+
+ protected abstract createPizza(type: string): Pizza | null;
+}
+
+class NYPizzaStore extends PizzaStore {
+ protected createPizza(type: string) {
+ const factory = new NYPizzaIngredientFactory();
+
+ switch (type) {
+ case "cheese":
+ const pizza = new CheesePizza(factory);
+ pizza.name = "뉴욕 스타일 치즈 피자";
+ return pizza;
+ case "clam":
+ const pizza = new ClamPizza(factory);
+ pizza.name = "뉴욕 스타일 조개 피자";
+ return pizza;
+ default:
+ return null;
+ }
+ }
+}
+```
+
+### 코드 설명
+
+- **간단한 팩토리 → 팩토리 메소드 → 추상 팩토리**로 점진적으로 발전하는 구조다. 각 단계마다 해결하는 문제의 범위가 넓어진다.
+- **팩토리 메소드 패턴**에서 `orderPizza()`는 일종의 템플릿 메소드 역할을 한다. 주문 프로세스(prepare → bake → cut → box)는 고정하면서, 어떤 피자를 만들지만 서브클래스에 맡긴다.
+- **추상 팩토리 패턴**에서 `CheesePizza`는 지역별 클래스(`NYStyleCheesePizza`, `ChicagoStyleCheesePizza`)를 따로 만들 필요가 없다. 원재료 팩토리만 바꾸면 같은 `CheesePizza` 클래스로 뉴욕 스타일과 시카고 스타일을 모두 만들 수 있다.
+- **팩토리 메소드 + 추상 팩토리 결합**: `NYPizzaStore`(팩토리 메소드)가 `NYPizzaIngredientFactory`(추상 팩토리)를 생성하여 피자에 주입한다. 두 패턴이 자연스럽게 함께 사용되는 사례다.
+
+---
+
+## 구현 방식 비교
+
+이 챕터에서 등장하는 세 가지 팩토리 관련 기법을 비교한다.
+
+| 구분 | 간단한 팩토리 | 팩토리 메소드 패턴 | 추상 팩토리 패턴 |
+| ----------------- | ------------------------------- | ------------------------------------------------------- | ----------------------------------------------------- |
+| 분류 | 프로그래밍 관용구 | 디자인 패턴 | 디자인 패턴 |
+| 객체 생성 방식 | 별도 팩토리 객체에 위임 | 서브클래스의 메소드 오버라이드(상속) | 팩토리 인터페이스를 구현한 객체에 위임(구성) |
+| 생성 대상 | 한 가지 제품 | 한 가지 제품 | 서로 연관된 제품군 전체 |
+| 확장 방법 | 팩토리 코드를 직접 수정 | 새로운 서브클래스 추가 | 새로운 구상 팩토리 추가 |
+| 유연성 | 낮음 (변경 시 팩토리 수정 필요) | 높음 (서브클래스 추가로 확장) | 높음 (팩토리 교체로 제품군 전체 변경) |
+| 제품 추가 시 영향 | 팩토리 코드 수정 | 서브클래스에 조건 추가 | 팩토리 인터페이스 변경 필요 (모든 구상 팩토리에 영향) |
+| 적합한 상황 | 간단한 객체 생성 캡슐화 | 어떤 구상 클래스를 만들지 서브클래스에서 결정해야 할 때 | 연관된 제품군을 일관성 있게 생성해야 할 때 |
+
+---
+
+## 의존성 뒤집기 원칙 (DIP)
+
+이 챕터에서 새로 등장하는 핵심 디자인 원칙이다.
+
+> **의존성 뒤집기 원칙(Dependency Inversion Principle)**
+>
+> 추상화된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만든다.
+
+팩토리 패턴 적용 전에는 `PizzaStore`가 모든 구상 피자 클래스(`NYStyleCheesePizza`, `ChicagoStyleCheesePizza` 등)에 직접 의존했다.
+
+팩토리 메소드 패턴을 적용하면 `PizzaStore`는 추상 클래스인 `Pizza`에만 의존하고, 구상 피자 클래스들도 `Pizza`에 의존한다.
+
+고수준 모듈과 저수준 모듈 모두 추상화에 의존하게 되면서 의존성이 "뒤집힌다".
+
+**DIP를 지키기 위한 가이드라인**
+
+- 변수에 구상 클래스의 레퍼런스를 저장하지 않는다. 팩토리를 사용하여 구상 클래스 레퍼런스가 변수에 직접 저장되는 것을 방지한다.
+- 구상 클래스에서 유도된 클래스를 만들지 않는다. 인터페이스나 추상 클래스처럼 추상화된 것으로부터 클래스를 만든다.
+- 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드하지 않는다. 오버라이드가 필요하다면 베이스 클래스의 추상화가 부족한 것이다.
+
+이 가이드라인은 항상 완벽하게 지킬 수 있는 규칙이 아니라, 지향해야 할 방향이다.
+
+중요한 것은 원칙을 의식하면서 디자인하고, 위반하는 부분을 명확히 인지하는 것이다.
+
+---
+
+## 실전 활용
+
+### 언제 사용하면 좋을까?
+
+- **간단한 팩토리**: 객체 생성 코드가 여러 곳에 중복되어 있을 때, 한 곳으로 모아 관리하고 싶을 때
+- **팩토리 메소드**: 어떤 구상 클래스를 생성할지 미리 알 수 없거나, 생성 결정을 서브클래스에 맡기고 싶을 때. 프레임워크를 만들 때 특히 유용하다.
+- **추상 팩토리**: 서로 연관된 제품군을 일관성 있게 생성해야 할 때. 플랫폼별 UI 컴포넌트, 지역별 원재료 등 "제품군 단위의 교체"가 필요한 상황에 적합하다.
+
+### 장단점
+
+**장점**
+
+- 객체 생성 코드를 캡슐화하여 클라이언트와 구상 클래스를 분리한다.
+- DIP를 준수한다. 고수준 모듈이 저수준 모듈의 구상 클래스에 직접 의존하지 않는다.
+- 팩토리 메소드 패턴은 새로운 제품 추가 시 기존 코드를 수정하지 않고 서브클래스만 추가하면 되므로 OCP를 준수한다.
+- 추상 팩토리 패턴은 제품군의 일관성을 보장한다. 뉴욕 팩토리에서 시카고 원재료가 섞여 나오는 일을 방지할 수 있다.
+
+**단점**
+
+- 팩토리 메소드 패턴은 제품 하나를 추가할 때마다 생산자 서브클래스를 만들어야 하므로 클래스 수가 증가한다.
+- 추상 팩토리 패턴은 제품군에 새로운 종류의 제품을 추가할 때 팩토리 인터페이스 자체를 변경해야 하며, 이는 모든 구상 팩토리에 영향을 미친다.
+- 단순한 상황에서 팩토리 패턴을 적용하면 불필요한 복잡성이 추가될 수 있다.
+
+### 실제 적용 사례
+
+- **DOM의 `document.createElement()`**: 태그 이름(문자열)을 받아 해당 HTML 요소 인스턴스를 반환하는 간단한 팩토리의 전형적인 예시다.
+- **React의 `createElement()`**: JSX가 컴파일되면 `React.createElement()` 호출로 변환된다. 컴포넌트 타입(문자열 또는 함수)에 따라 다른 종류의 ReactElement를 생성하는 팩토리 메소드 역할을 한다.
+- **크로스 플랫폼 UI 라이브러리**: 운영체제별로 다른 UI 컴포넌트(버튼, 스크롤바, 메뉴 등)를 생성해야 할 때 추상 팩토리 패턴이 사용된다. `WindowsUIFactory`와 `MacUIFactory`가 동일한 인터페이스로 각 플랫폼에 맞는 컴포넌트군을 생산한다.
+- **ORM의 Database Dialect**: TypeORM이나 Prisma 같은 ORM에서 데이터베이스 종류(MySQL, PostgreSQL 등)에 따라 다른 쿼리 빌더와 타입 매핑을 생성하는 구조가 추상 팩토리 패턴의 변형이다.
+
+---
+
+## 핵심 정리
+
+- 팩토리 패턴은 객체 생성을 캡슐화하여 클라이언트 코드와 구상 클래스를 분리한다. `new`를 직접 사용하는 대신 팩토리에 위임함으로써 변경에 유연하게 대응할 수 있다.
+- 간단한 팩토리는 관용구, 팩토리 메소드는 상속을 활용한 패턴, 추상 팩토리는 구성을 활용한 패턴이다. 팩토리 메소드는 "하나의 제품"을, 추상 팩토리는 "연관된 제품군"을 생성하는 데 초점이 있다.
+- 의존성 뒤집기 원칙(DIP)에 따르면 고수준 모듈과 저수준 모듈 모두 추상화에 의존해야 한다. 팩토리 패턴은 이 원칙을 실현하는 대표적인 기법이다.
+- 추상 팩토리의 각 메소드는 사실상 팩토리 메소드로 구현되는 경우가 많다. 두 패턴은 대립하는 것이 아니라 자연스럽게 함께 사용된다.
+
+---
+
+## 함께 등장한 디자인 원칙
+
+| 원칙 | 이 패턴에서의 적용 |
+| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
+| 바뀌는 부분은 캡슐화한다 | 객체 생성 코드(바뀌는 부분)를 팩토리로 분리하여 캡슐화 |
+| 상속보다는 구성을 활용한다 | 추상 팩토리 패턴에서 팩토리 객체를 구성(Composition)으로 주입하여 제품군을 교체 |
+| 구현보다는 인터페이스에 맞춰서 프로그래밍한다 | 클라이언트가 구상 클래스가 아닌 Pizza, PizzaIngredientFactory 등 추상 타입에만 의존 |
+| 클래스는 확장에 열려 있고 변경에 닫혀 있어야 한다 (OCP) | 새로운 피자 스타일 추가 시 기존 PizzaStore 코드 변경 없이 서브클래스만 추가 |
+| **추상화된 것에 의존하게 만들고 구상 클래스에 의존하지 않게 만든다 (DIP)** | 고수준(PizzaStore)과 저수준(구상 피자)이 모두 추상 클래스 Pizza에 의존. 팩토리를 통해 구상 클래스 직접 참조를 제거 |
+
+---
+
+## 관련 패턴
+
+- **템플릿 메소드 패턴 (Template Method)**: 팩토리 메소드 패턴의 `orderPizza()`는 사실상 템플릿 메소드다. 알고리즘의 골격(주문 프로세스)을 정의하고, 일부 단계(피자 생성)를 서브클래스에 맡긴다.
+- **빌더 패턴 (Builder)**: 팩토리 패턴이 "어떤 제품을 만들지"를 결정한다면, 빌더 패턴은 "복잡한 제품을 어떤 순서로 조립할지"에 초점을 둔다. 데코레이터로 음료를 감싸던 것처럼 피자 재료를 단계별로 조합하는 데 빌더 패턴을 활용할 수 있다(14장에서 다룬다).
+- **싱글턴 패턴 (Singleton)**: 팩토리 객체가 하나만 존재해야 하는 경우 싱글턴 패턴과 결합하여 사용하기도 한다.
+- **데코레이터 패턴 (Decorator)**: 3장에서 데코레이터 객체를 여러 겹 감싸는 코드가 복잡해지는 문제를 언급했다. 팩토리 패턴으로 데코레이터의 생성과 조합을 캡슐화하면 이 문제를 해결할 수 있다.