Abstract Factory Pattern
Abstract Factory Pattern 는 관련 객체들의 계열 (Product Family) 생성을 추상화하는 패턴으로, 클라이언트는 구체 클래스에 의존하지 않고 팩토리 인터페이스에만 의존해 객체를 생성한다. Abstract Factory 와 Concrete Factory, Abstract Product 와 Concrete Product, Client 로 구성되며, 클라이언트는 Abstract Factory 에 팩토리 구현체를 주입받아 원하는 제품 계열을 생성할 수 있다. 이는 제품 간 일관성 유지, 다양한 제품군 전환, 테스트 유연성 향상 등에 강점을 제공한다.
핵심 개념
Abstract Factory Pattern(추상 팩토리 패턴) 은 관련된 객체들의 집합을 구체 클래스를 지정하지 않고 생성할 수 있는 인터페이스를 제공하는 생성 패턴이다.
기본 개념
- 추상 팩토리 (Abstract Factory): 관련 객체들의 패밀리를 생성하는 인터페이스
- 구체 팩토리 (Concrete Factory): 특정 제품군을 생성하는 구현체
- 추상 제품 (Abstract Product): 제품들의 공통 인터페이스
- 구체 제품 (Concrete Product): 실제 생성되는 객체들
- 제품군 (Product Family): 함께 사용되도록 설계된 관련 객체들의 집합
- 클라이언트 (Client): 팩토리를 통해 객체를 사용하는 코드
- 클라이언트 분리: 구체적인 구현부로부터 독립적인 클라이언트 코드
심화 개념
- 팩토리의 팩토리: 여러 팩토리를 관리하는 상위 수준의 추상화
- 제품 일관성 (Product Consistency): 같은 패밀리 내 객체들의 호환성 보장
- 런타임 구성: 실행 시점에서의 동적 팩토리 선택
- 확장성 캡슐화: 새로운 제품군 추가 시 기존 코드 변경 최소화
의도 (Intent)
구체 클래스를 지정하지 않고, 관련된 객체들의 집합 (제품군) 을 생성할 수 있는 인터페이스를 제공하되, 구체적인 클래스는 명시하지 않는다.
다른 이름 (Also Known As)
- Kit Pattern
- Family Factory Pattern
- Toolkit Pattern
동기 (Motivation / Forces)
- 제품군 일관성: 관련된 제품들이 함께 사용되어야 하는 제약
- 플랫폼 독립성: 다양한 환경에서 동일한 인터페이스 제공 필요
- 확장성 요구: 새로운 제품군 추가 시 기존 코드 영향 최소화
- 구현 은닉: 클라이언트가 구체적인 구현에 의존하지 않도록 하는 필요성
적용 가능성 (Applicability)
- 시스템 독립성: 객체 생성, 구성, 표현 방식과 무관한 시스템 구축
- 제품군 선택: 여러 제품군 중 하나를 선택하여 시스템 구성
- 제품 일관성: 관련 제품들이 함께 사용되도록 제약 적용
- 라이브러리 제공: 구현이 아닌 인터페이스만 노출하는 라이브러리
패턴이 해결하고자 하는 설계 문제
- 플랫폼 종속성: 특정 플랫폼에 종속된 객체 생성 로직
- 제품군 불일치: 서로 다른 제품군의 객체들이 혼재하여 사용되는 문제
- 확장성 부족: 새로운 제품군 추가 시 기존 코드의 광범위한 수정
- 객체 생성 복잡성: 관련 객체들의 복잡한 생성 과정과 의존성
협력 (Collaboration)
- 런타임 인스턴스: ConcreteFactory 클래스의 인스턴스가 런타임에 생성
- 제품 생성: 구체적 팩토리가 특정 구현을 갖는 제품 객체 생성
- 팩토리 선택: 서로 다른 제품 객체를 위해 다른 구체적 팩토리 사용
- 책임 위임: AbstractFactory 가 제품 생성 책임을 ConcreteFactory 에 위임
실무 구현 연관성
핵심 개념들이 실무 구현과 연결되는 측면:
- 인터페이스 분리 원칙 (Interface Segregation Principle): 각 제품군별로 독립적인 인터페이스 제공
- 의존성 역전 원칙 (Dependency Inversion Principle): 구체 클래스가 아닌 추상화에 의존
- 개방 - 폐쇄 원칙 (Open-Closed Principle): 새로운 제품군 추가 시 기존 코드 수정 불필요
- 단일 책임 원칙 (Single Responsibility Principle): 각 팩토리는 하나의 제품군만 담당
배경
객체 지향 시스템에서 관련 객체들의 패밀리를 생성해야 할 때, 구체적인 클래스를 명시하면 코드가 환경에 종속되고 확장성이 떨어짐. 이를 해결하기 위해 객체 생성 로직을 추상화하는 패턴이 필요해짐.
목적 및 필요성
- 제품군의 일관성 보장: 관련된 객체들이 함께 사용될 수 있도록 보장
- 플랫폼 독립성: 다양한 플랫폼에서 동일한 인터페이스로 서로 다른 구현 제공
- 확장성: 새로운 제품군 추가 시 기존 코드 수정 최소화
- 의존성 분리: 클라이언트 코드와 구체적인 구현 간의 결합도 감소
주요 기능 및 역할
기능
- 객체 생성 캡슐화: 객체 생성 과정을 캡슐화하여 클라이언트로부터 숨김
- 제품군 일관성 보장: 동일한 제품군 내의 객체들만 함께 사용되도록 보장
- 런타임 제품군 교체: 실행 중에 사용할 제품군을 변경 가능
- 확장성 제공: 새로운 제품군 추가 시 기존 코드 수정 최소화
역할
- AbstractFactory: 제품 생성 메서드들의 인터페이스 정의
- ConcreteFactory: 특정 제품군의 객체들을 실제로 생성
- AbstractProduct: 제품들의 공통 인터페이스 정의
- ConcreteProduct: 실제 제품 객체들의 구현
- Client: 팩토리와 제품 인터페이스만 사용하여 비즈니스 로직 수행
특징
- 인터페이스 기반: 모든 상호작용이 추상 인터페이스를 통해 이루어짐
- 제품군 단위 생성: 개별 객체가 아닌 관련 객체들의 집합을 생성
- 런타임 결정: 실행 시점에 구체적인 팩토리 결정
- 확장 가능: 새로운 제품군 추가가 용이
핵심 원칙
- 추상화 원칙: 구체적인 구현보다는 추상 인터페이스에 의존
- 캡슐화 원칙: 객체 생성 과정을 팩토리 내부에 숨김
- 일관성 원칙: 동일한 제품군 내의 객체들만 함께 사용
- 확장성 원칙: 기존 코드 수정 없이 새로운 기능 추가 가능
SOLID 원칙의 관계
원칙 | 적용 예시 |
---|---|
SRP (Single Responsibility Principle) | 각 팩토리는 생성 책임만 수행 |
OCP (Open/Closed Principle) | 새로운 팩토리 추가 시 기존 클라이언트 변경 불필요 |
DIP (Dependency Inversion Principle) | 클라이언트는 추상 팩토리 인터페이스에 의존 |
ISP (Interface Segregation Principle) | 팩토리 인터페이스는 제품군 단위로 분리 가능 |
LSP (Liskov Substitution Principle) | 추상 팩토리 대체에 있어 기능 보장 가능 |
주요 원리
- 클라이언트는 AbstractFactory 인터페이스를 통해 객체 생성
- 구체 팩토리 (ConcreteFactory) 는 제품군별 객체를 생성해 반환
- 클라이언트는 추상 제품 타입만 사용하며, 구체 클래스는 몰라도 됨
- 제품군 교체 시 ConcreteFactory 만 교체하면 됨
참여자들 간의 상호작용 방식
graph LR A[Client Request] --> B{Factory Selection} B --> C[Windows Factory] B --> D[macOS Factory] B --> E[Linux Factory] C --> F[Windows Products] D --> G[macOS Products] E --> H[Linux Products] F --> I[Client Usage] G --> I H --> I I --> J[Consistent Interface]
상호작용 패턴:
- 초기화 단계: 환경 감지 후 적절한 팩토리 선택
- 생성 단계: 팩토리를 통한 관련 제품들의 일괄 생성
- 사용 단계: 추상 인터페이스를 통한 제품 조작
- 교체 단계: 필요시 다른 팩토리로 전환
문제를 해결하기 위한 설계 구조와 관계
sequenceDiagram participant Client participant AbstractFactory participant ConcreteFactory participant AbstractProduct participant ConcreteProduct Client->>AbstractFactory: getFactory() AbstractFactory-->>ConcreteFactory: returns instance Client->>ConcreteFactory: createProduct() ConcreteFactory-->>ConcreteProduct: instantiate ConcreteProduct-->>Client: returns as AbstractProduct Client->>AbstractProduct: use()
설계 구조의 핵심 관계:
- 위임 관계: 클라이언트가 구체적 생성을 팩토리에 위임
- 상속 관계: 구체적 팩토리가 추상 팩토리를 상속하여 구현
- 구현 관계: 구체적 제품이 추상 제품 인터페이스를 구현
- 조합 관계: 팩토리가 여러 관련 제품들을 함께 생성
작동 메커니즘
sequenceDiagram participant Client participant AbstractFactory participant ConcreteFactoryA participant ConcreteProductA1 participant ConcreteProductA2 participant ConcreteFactoryB participant ConcreteProductB1 participant ConcreteProductB2 Note over Client: 팩토리 선택 및 초기화 Client->>ConcreteFactoryA: new ConcreteFactoryA() ConcreteFactoryA-->>Client: ConcreteFactoryA 인스턴스 Note over Client: 제품군 A의 제품들 생성 Client->>ConcreteFactoryA: createProductType1() ConcreteFactoryA->>ConcreteProductA1: new ConcreteProductA1() ConcreteProductA1-->>ConcreteFactoryA: ConcreteProductA1 인스턴스 ConcreteFactoryA-->>Client: ProductType1 인터페이스로 반환 Client->>ConcreteFactoryA: createProductType2() ConcreteFactoryA->>ConcreteProductA2: new ConcreteProductA2() ConcreteProductA2-->>ConcreteFactoryA: ConcreteProductA2 인스턴스 ConcreteFactoryA-->>Client: ProductType2 인터페이스로 반환 Note over Client: 다른 제품군으로 전환 Client->>ConcreteFactoryB: new ConcreteFactoryB() ConcreteFactoryB-->>Client: ConcreteFactoryB 인스턴스 Note over Client: 제품군 B의 제품들 생성 Client->>ConcreteFactoryB: createProductType1() ConcreteFactoryB->>ConcreteProductB1: new ConcreteProductB1() ConcreteProductB1-->>ConcreteFactoryB: ConcreteProductB1 인스턴스 ConcreteFactoryB-->>Client: ProductType1 인터페이스로 반환 Client->>ConcreteFactoryB: createProductType2() ConcreteFactoryB->>ConcreteProductB2: new ConcreteProductB2() ConcreteProductB2-->>ConcreteFactoryB: ConcreteProductB2 인스턴스 ConcreteFactoryB-->>Client: ProductType2 인터페이스로 반환
- 팩토리 선택: 클라이언트가 필요한 제품군에 맞는 구체 팩토리를 선택
- 제품 생성 요청: 추상 인터페이스를 통해 제품 생성 메서드 호출
- 구체 제품 생성: 각 팩토리가 자신의 제품군에 맞는 구체 제품들을 생성
- 인터페이스 반환: 클라이언트에게는 추상 인터페이스로 제품을 반환
패턴 적용의 결과와 트레이드오프
긍정적 결과
- 유연성 증가: 런타임에 제품군 교체 가능
- 일관성 보장: 제품군 내 객체들의 호환성 확보
- 확장성 향상: 새로운 제품군 추가가 기존 코드에 미치는 영향 최소화
트레이드오프
- 복잡성 vs 유연성: 코드 구조가 복잡해지지만 높은 유연성 획득
- 초기 비용 vs 장기 이익: 초기 개발 시간이 증가하지만 유지보수성 향상
- 성능 vs 추상화: 간접 호출로 인한 성능 오버헤드 vs 높은 추상화 수준
패턴에 참여하는 클래스와 객체들
구성 요소 | 역할 | 책임 | 특징 |
---|---|---|---|
AbstractFactory | 제품 생성 메서드들의 인터페이스 정의 | 제품군 생성의 계약 명시 | 제품군별 생성 메서드를 순수 가상 함수로 정의 |
ConcreteFactory | 특정 제품군의 실제 생성 구현 | 관련 제품들 (Button, Checkbox 등) 의 일관된 생성 | 하나의 제품군에 특화되어 동작 |
AbstractProduct | 제품의 공통 인터페이스 정의 | 제품 간의 표준 동작 정의 | 제품 타입별 (Button, Checkbox 등) 로 별도 정의 |
ConcreteProduct | 실제 제품의 구현 | 추상 제품 인터페이스의 기능 구현, 플랫폼별 차별화 제공 | 특정 팩토리에서만 생성되며, 기능은 추상 제품을 기반으로 확장 |
Client | 추상 인터페이스를 통해 제품을 사용 | 팩토리를 이용해 제품을 생성하고 비즈니스 로직 수행 | 구체적 팩토리/제품에 대한 의존 없이 추상화에만 의존 |
구현 기법
구현 기법 | 정의 | 구성 요소 | 목적 | 실제 예시 |
---|---|---|---|---|
** 기본 구현 기법** | 인터페이스 기반의 고정된 팩토리 클래스와 제품군 구조 | 추상 팩토리, 구체 팩토리, 제품 인터페이스, 구체 제품 | 제품군 간 일관된 생성 구조 제공 | GUI 위젯 (MacButton, WinButton) |
** 팩토리 등록 기법** | 팩토리를 레지스트리에 등록하고, 조건에 따라 런타임에 팩토리를 선택 | 팩토리 맵, 등록 API, 조건 분기 로직 | 플러그인 구조, 런타임 확장성 | JDBC 드라이버, 브라우저 플러그인 |
** 파라미터화된 팩토리** | 파라미터 (키) 를 받아 하나의 팩토리 메서드에서 다양한 제품을 생성 | 조건문/딕셔너리, 제품 식별자, 단일 팩토리 메서드 | 코드 수 감소, 분기 로직 통합 | 몬스터 생성 팩토리, DB 커넥션 팩토리 |
** 싱글톤 팩토리** | 팩토리를 애플리케이션 전역에서 하나만 생성하고 공유하는 구조 | 정적 인스턴스, getInstance(), 비공개 생성자 | 전역 상태 공유, 메모리 절감 | LoggerFactory, ConfigFactory |
** Reflection 기반 기법** | 클래스명을 문자열로 받아 동적으로 팩토리 또는 제품 객체를 생성 | 클래스 매핑, getattr() 또는 __import__() 등 | 동적 생성, 제품 추가 시 코드 수정 최소화 | Python 모듈 로딩, 자바의 Class.forName |
** 프로토타입 기반 기법** | 초기 템플릿 객체를 복제하여 새 객체 생성 (복잡한 객체 복사에 적합) | 원형 객체, copy() 혹은 .clone() 메서드 | 복잡한 객체 복사 비용 절감 | 게임 캐릭터, UI 템플릿 복사 |
DSL 기반 팩토리 | 선언적 구성 (DSL) 으로 팩토리 로직 정의 후 런타임에 파싱하여 객체 생성 | 구성 파일 (JSON/YAML), 파서, 런타임 생성기 | 설정 기반 확장 가능, UI/워크플로우 제너레이터 | 템플릿 엔진, UI DSL (Flutter, Unity 등) |
기본 구현 기법 (Standard)
|
|
팩토리 등록 기법 (Registry)
|
|
파라미터화된 팩토리
싱글톤 팩토리
리플렉션 기반
프로토타입 기반 기법
DSL 기반 팩토리
|
|
열거형 기반 팩토리 선택
|
|
설정 기반 팩토리 로딩
|
|
유사하거나 관련된 패턴들
구분 | 패턴 | 관계 타입 | 설명 | 주요 차이점 | 조합 시나리오 |
---|---|---|---|---|---|
객체 생성 | Factory Method | 협력/구성 관계 | Abstract Factory 의 구성 요소로 활용 | 단일 제품 vs 제품군 생성 | Abstract Factory 내부에서 Factory Method 패턴 사용 |
객체 생성/조립 | Builder | 협력/조합 관계 | 복잡한 제품 생성 시 함께 사용 | 제품군 선택 vs 제품 조립 | GUI 프레임워크에서 컴포넌트 생성 및 조립 |
객체 생성/관리 | Prototype | 협력/대체 관계 | 팩토리 내부에서 복제 기반 생성 | 새 인스턴스 vs 복제 기반 생성 | 비용이 큰 객체의 효율적 생성 |
객체 생명주기 | Singleton | 협력/보완 관계 | 팩토리 인스턴스의 유일성 보장 | 다중 인스턴스 vs 단일 인스턴스 | 전역 팩토리 접근점 제공 |
인터페이스 단순화 | Facade | 대안/경쟁 관계 | 간단한 객체 생성 시 대안 | 복잡한 제품군 vs 단순 인터페이스 | 서브시스템 객체 생성 단순화 |
Factory Method
Abstract Factory 는 여러 Factory Method 들의 집합으로 구현되며, 각 제품 생성 메서드가 Factory Method 패턴을 따른다.
|
|
- Abstract Factory 의 각
create_*
메서드가 Factory Method 패턴을 구현 - 템플릿 메서드
create_database_toolkit()
이 여러 Factory Method 를 조합하여 완전한 제품군 생성 - 각 구체적 팩토리에서 Factory Method 들을 오버라이드하여 특정 제품군 생성
Prototype
Abstract Factory 에서 Prototype 을 사용하여 미리 구성된 객체들을 복제하는 방식으로 제품을 생성한다.
|
|
- Abstract Factory 가 플랫폼별 UI 컴포넌트 생성을 담당
- Prototype Registry 가 미리 구성된 템플릿 객체들을 관리
- 객체 생성 시 새로 인스턴스를 만드는 대신 프로토타입을 복제하여 성능 향상
- 복제된 객체를 필요에 따라 커스터마이징하여 다양한 변형 생성
Singleton
구체적 팩토리 인스턴스는 보통 싱글톤으로 구현되어 시스템 전체에서 하나의 팩토리만 사용하도록 보장한다.
|
|
- Abstract Factory 의 구체적 구현체들이 Singleton 패턴을 적용하여 시스템 전체에서 단일 인스턴스만 존재
- 스레드 안전한 Singleton 구현으로 멀티스레드 환경에서도 안전하게 동작
- Factory Provider 도 Singleton 으로 구현하여 환경별 팩토리 관리의 일관성 보장
- 메모리 효율성과 상태 일관성을 통한 시스템 안정성 확보
Builder
Abstract Factory 가 제품군 선택을 담당하고, Builder 가 각 제품의 복잡한 조립 과정을 담당한다.
|
|
- Abstract Factory 가 어떤 데이터베이스 시스템 (MySQL/PostgreSQL) 을 구성할지 결정
- Builder 가 선택된 시스템의 복잡한 설정과 최적화 과정을 단계별로 수행
- Director 가 다양한 구성 시나리오 (개발/운영/고성능) 에 따른 빌드 과정 조율
Factory Method
복잡한 서브시스템의 객체 생성을 단순화하고 싶을 때 Abstract Factory 대신 Facade Pattern 을 사용할 수 있다.
|
|
- Abstract Factory: 높은 유연성과 확장성을 제공하지만 클라이언트가 복잡한 구조를 이해해야 함
- Facade: 복잡한 서브시스템을 단순한 인터페이스로 감싸서 사용성을 높이지만 유연성이 제한됨
- 선택 기준:
- 다양한 제품군과 높은 커스터마이징이 필요한 경우 → Abstract Factory
- 복잡한 시스템의 일반적인 사용 패턴만 필요한 경우 → Facade
장점
항목 | 설명 | 관련 원인 또는 기반 원칙 |
---|---|---|
제품군 일관성 보장 | 동일 팩토리에서 생성된 객체들이 스타일·기능적으로 호환되어 UI/UX 및 동작 일관성 유지 | 추상 팩토리 인터페이스가 동일 제품군 생성만 허용 |
구체 클래스 은닉 | 클라이언트가 구체 클래스 이름이나 생성 방식에 대해 알 필요 없이 사용 가능 | 추상 인터페이스 기반 접근 |
결합도 감소 | 클라이언트가 인터페이스에만 의존하므로 구체 구현과의 결합이 줄어듬 | DIP(의존성 역전 원칙), SRP(단일 책임 원칙) |
확장성 향상 | 새로운 제품군을 추가할 때 기존 클라이언트 코드 수정 없이 확장 가능 | OCP(개방 폐쇄 원칙) 준수, 팩토리 교체로 확장 가능 |
플랫폼 독립성 확보 | 동일 클라이언트 코드로 Windows, Mac, Linux 등 다양한 플랫폼 대상의 객체 생성 가능 | 추상화된 팩토리 구성 |
유지보수성 향상 | 객체 생성 로직이 팩토리에 집중되므로 수정이 용이하고 영향 범위가 제한됨 | 생성 책임의 분리 (SRP), 팩토리 캡슐화 구조 |
테스트 용이성 증가 | DI(의존성 주입) 를 통해 Mock Factory 또는 Stub 으로 테스트 가능 | 객체 생성 제어권이 클라이언트 외부에 있음 |
제품군 교체 용이성 | 팩토리 인스턴스만 변경하면 전체 제품군 교체가 가능하여 UI/엔진/테마 전환에 용이 | 런타임 팩토리 교체 구조 |
타입 안전성 제공 | 컴파일 타임에 제품군 간 타입 불일치 방지 가능 | 팩토리 메서드 시그니처로 타입 고정 |
모듈화 및 재사용성 증가 | 제품 생성 책임을 별도 팩토리로 분리함으로써 클라이언트 모듈의 독립성과 재사용성 향상 | 객체 생성 코드의 집중화와 구조적 분리 |
- 일관성: 제품군 단위의 호환성 유지
- 유연성: 교체와 확장이 클라이언트 영향 없이 가능
- 테스트성: 주입 기반 테스트 전략 지원
- 설계 원칙 준수: SRP, OCP, DIP 등 주요 원칙 내재
단점과 문제점 그리고 해결방안
단점
항목 | 설명 | 해결 방안 |
---|---|---|
클래스 수 증가 | 팩토리, 제품 등 관련 클래스와 인터페이스 수가 많아져 복잡도 증가 | 코드 제너레이션 도구 활용, 모듈 구조 및 네이밍 일관성 유지 |
구조 복잡성 | 추상 계층과 관계 구조가 복잡하여 초급 개발자 이해 어려움 | 도식화된 문서, 예제 중심 교육, 디자인 가이드 제공 |
과도한 추상화 | 간단한 문제에 적용 시 오히려 설계 과잉이 되어 유지보수 어려움 | 요구 사항 및 시스템 규모에 따라 Factory Method 로 대체 검토 |
확장 어려움 | 제품군 추가 시 인터페이스 및 모든 팩토리 구현체를 수정해야 하는 부담 | 디폴트 구현 또는 Optional 인터페이스 메서드 제공, 유연한 인터페이스 설계 |
메모리 오버헤드 | 불필요한 객체 생성으로 인한 리소스 낭비 가능 | 객체 풀링 (Pooling), Flyweight Pattern 적용 |
문제점
항목 | 원인 | 영향 | 탐지 및 진단 | 예방 방법 | 해결 방법 및 기법 |
---|---|---|---|---|---|
팩토리 선택 오류 | 설정값 오류, 조건문 잘못된 분기 | 의도하지 않은 제품군 생성 | 유닛 테스트, 로깅 | 조건 로직 검증, 타입 기반 분기 명확화 | 팩토리 검증 로직 추가, 레지스트리 기반 팩토리 매핑 적용 |
제품 불일치 | 서로 다른 제품군의 객체를 혼용 | 런타임 호환성 오류 | 정적 타입 체크, 컴파일 오류 탐지 | 동일 제품군 전용 팩토리만 사용, 생성 책임 명확화 | 제품군 태그 기반 검증 메커니즘, 타입 안전한 팩토리 구성 |
인터페이스 변경 부담 | 추상 팩토리에 메서드 추가 필요 시 전체 구현체 영향 | 구현체 재작성 필요 | 코드 리뷰 및 인터페이스 변경 추적 도구 | 확장 고려한 분리 인터페이스 설계, 인터페이스 안정성 확보 | 인터페이스 버전 관리, 파라미터화된 팩토리 사용 |
순환 의존성 | 팩토리 간 상호 참조 및 의존 관계 형성 | 객체 생성 실패, 사이클 오류 | 의존성 분석 도구, DI 컨테이너 확인 | 의존 방향 단방향 유지, 책임 분리 설계 | 계층화된 팩토리 구조 설계, DI/IoC 컨테이너 활용 |
팩토리 난립/폭주 | 제품군 수 증가로 다양한 팩토리 생김 | 관리 어려움, 유지보수 비용 증가 | 구조 시각화, 구성도 분석 | 팩토리 그룹화 및 메타팩토리 도입 | 추상화 계층 통합, 팩토리 컴포지션 또는 Provider 패턴 적용 |
메모리 누수 | 팩토리 또는 제품 객체의 라이프사이클 미관리 | 성능 저하 및 리소스 부족 | 메모리 프로파일링, GC 로그 분석 | 객체 생명주기 명시적 관리 | 자원 해제 로직 추가, GC 친화적 설계, WeakRef 활용 등 |
도전 과제
도전 과제 | 원인 | 영향 | 예방 방법 | 해결 방법 및 기법 |
---|---|---|---|---|
제품군 확장 시 모든 팩토리 수정 필요 | 추상 팩토리 인터페이스가 고정되어 새로운 제품 추가 시 전면 수정 필요 | 구현 클래스의 확장 부담, 코드 변경 범위 확장 | 유연한 인터페이스 분리 설계, Optional 메서드 활용 | 파라미터화된 팩토리, default method, Fallback 구조 적용 |
클래스 수 증가로 인한 구조 복잡도 | 제품군 + 팩토리 수 증가, 세분화된 인터페이스 구성 | 코드 가독성 저하, 유지보수성 저하 | 문서화 및 패키지 구조 명확화, 네이밍 컨벤션 통일 | 코드 생성 도구 활용, DI 컨테이너 조합, 구조 시각화 도구 도입 |
런타임 팩토리 선택의 복잡도 증가 | 동적 환경에서 조건문 또는 설정 기반으로 팩토리 선택 필요 | 팩토리 선택 오류 발생 가능성, 테스트 난이도 증가 | 설정 기반 매핑, 타입 기반 팩토리 선택 기준 마련 | FactoryProvider 또는 레지스트리 기반 팩토리 매핑 전략 |
마이크로서비스/클라우드 환경과의 결합 어려움 | 서비스 분산 환경, 컨테이너 기반 아키텍처의 동적 스케일링 | 전역 팩토리 관리 어려움, 인스턴스 상태 불일치 발생 가능 | Stateless 설계, DI 기반 팩토리 구성 | 서비스 레지스트리 및 클라우드 서비스와 연동된 분산 팩토리 구현 |
실시간 시스템에서의 객체 생성 오버헤드 | 객체 생성 비용 및 초기화 지연 | 성능 저하, 응답 시간 증가 | 최소 생성 전략 도입, 미리 준비된 객체 활용 | 객체 풀링 (Pooling), 지연 초기화 (Lazy Initialization) 적용 |
테스트 환경에서의 Mock 객체 주입 어려움 | 팩토리 내부에 생성 로직이 고정되어 테스트 주입 어려움 | 테스트 격리 어려움, 테스트 신뢰도 저하 | 인터페이스 기반 팩토리 추상화, 테스트 전용 팩토리 설계 | DI 컨테이너 활용, Mock Factory 또는 Factory Override 전략 적용 |
인터페이스 변경 시 전체 구현체 영향 | 단일 인터페이스에 다수의 제품 생성 메서드 포함 | 모든 팩토리 구현체에 영향 발생 | 인터페이스 분리 원칙 (ISP) 적용, 단일 책임 유지 | 인터페이스 세분화 및 버전 관리, 플러그인 기반 구조 도입 |
순환 의존성 문제 | 서로 다른 팩토리가 내부적으로 참조 관계 형성 | 객체 생성 시 오류, 의존성 꼬임 | DI 원칙 적용, 참조 방향 일관화 | 계층화된 팩토리 구성, Service Locator 또는 Factory Chain 패턴 적용 |
오버엔지니어링 위험 | 간단한 구조에도 무리하게 추상 팩토리 적용 | 불필요한 복잡성, 생산성 저하 | 요구사항 기반 사전 설계 검토 | Factory Method → 필요 시 Abstract Factory 로 확장 전략 사용 |
유지보수 및 확장성 저하 | 과도한 수작업 클래스 추가, 인터페이스 의존 | 확장 어려움, 유지보수 비용 증가 | 제품군 증가 예측에 기반한 팩토리 추상화 수준 조절 | 코드 템플릿 자동화, 유닛 테스트 기반 리팩토링 루틴 확보 |
분류 기준에 따른 종류 및 유형
분류 기준 | 유형 | 설명 | 특징 |
---|---|---|---|
구현 방식 | 클래스 기반 | 클래스 상속을 통한 구현 | 정적 타입 안정성, 컴파일 타임 검증 |
구현 방식 | 인터페이스 기반 | 인터페이스 구현을 통한 구현 | 유연성, 다중 상속 효과 |
팩토리 생성 | 정적 팩토리 | 컴파일 타임에 팩토리 결정 | 성능 우수, 타입 안정성 |
팩토리 생성 | 동적 팩토리 | 런타임에 팩토리 결정 | 유연성, 확장성 |
제품 생성 | 즉시 생성 | 요청 즉시 객체 생성 | 단순함, 메모리 사용량 예측 가능 |
제품 생성 | 지연 생성 | 실제 사용 시점에 객체 생성 | 메모리 효율성, 초기화 시간 단축 |
실무 사용 예시
분야 | 사용 사례 | 조합 기술/패턴 | 목적 및 효과 |
---|---|---|---|
1. UI/GUI 개발 | 운영체제별 위젯/컴포넌트 생성 | Factory Method, Builder, MVC | 플랫폼별 UI 일관성, 크로스 플랫폼 호환성 |
Java Swing / Look & Feel | Abstract Factory | 테마 기반 UI 구성 지원 | |
웹 UI 프레임워크 구성 | DI Container, AOP | 다중 환경 대응 UI 로직 구성 | |
게임 UI 테마 적용 | Unity/Unreal + Theme Factory | 게임 내 UI 아트 스타일 일관성 | |
2. 데이터베이스 | RDBMS 커넥션 객체 팩토리 | JDBC, DAO, ORM | DB 벤더 독립성, DB 변경 유연성 |
NoSQL/RDB 동시 대응 드라이버 | Parameterized Factory | 복수 DB 대응 및 런타임 DB 선택 | |
ADO.NET Provider 구성 | .NET 기반 Factory + Adapter | DB 액세스 계층 캡슐화 | |
3. 클라우드/백엔드 | 클라우드 벤더별 클라이언트 구성 | Adapter, Strategy, Bridge | AWS/Azure 등 SDK 독립성 확보 |
API 버전별 핸들러 추상화 | Abstract Factory + Version Mapper | API 버전 전환 시 코드 변경 최소화 | |
로깅 시스템 백엔드 구성 | Strategy Pattern + Factory | 콘솔/파일/원격 로거 교체 유연성 | |
4. 게임 개발 | 레벨/테마 기반 적 캐릭터 생성 | Factory + Strategy, State Pattern | 게임 밸런싱, 다양성 보장 |
아이템/무기 스타일팩 생성 | Theme-aware Factory | 테마별 일관된 게임 요소 생성 | |
5. 웹 애플리케이션 | 템플릿 엔진/렌더링 컴포넌트 구성 | Template Engine + Factory | 다양한 템플릿 엔진과 통합 가능 |
멀티 테넌시 서비스 객체 주입 | DI, Plugin 기반 FactoryProvider | 테넌트별 환경 맞춤 서비스 제공 | |
6. IoT/임베디드 | 디바이스 타입별 드라이버 팩토리 | Protocol Factory (MQTT/CoAP) | 하드웨어 독립성, 통신 최적화 |
제조사별 센서 인터페이스 관리 | Adapter + Factory | 센서 교체 시 호환성 보장 | |
7. 테스트 환경 | Mock 객체 vs 실제 객체 팩토리 | DI 기반 Test Factory, Stub Factory | 테스트 유연성 향상, 테스트 코드 분리 |
테스트 환경 구성용 팩토리 교체 | 환경 프로파일 기반 구성 | 테스트/운영 환경 간 분리 및 검증 용이성 |
활용 사례
사례 1: 전자상거래 결제 시스템
대형 전자상거래 플랫폼에서 국가별로 다른 결제 시스템을 지원해야 하는 상황. 한국은 KakaoPay 와 Toss, 미국은 PayPal 과 Stripe, 일본은 Rakuten Pay 와 LINE Pay 를 지원해야 함.
시스템 구성
시스템 다이어그램
graph TB A[E-Commerce Platform] --> B[PaymentFactoryProvider] B --> C[KoreaPaymentFactory] B --> D[USPaymentFactory] B --> E[JapanPaymentFactory] C --> F[KakaoPayProcessor] C --> G[TossPayProcessor] D --> H[PayPalProcessor] D --> I[StripeProcessor] E --> J[RakutenPayProcessor] E --> K[LinePayProcessor] F --> L[PaymentProcessor Interface] G --> L H --> L I --> L J --> L K --> L
Workflow:
- 사용자 접속: 사용자의 국가 정보 확인 (IP 기반 또는 계정 설정)
- 팩토리 선택: 국가별 결제 팩토리 선택 (KoreaPaymentFactory)
- 결제 수단 선택: 사용자가 원하는 결제 수단 선택 (KakaoPay)
- 프로세서 생성: 팩토리에서 해당 결제 프로세서 객체 생성
- 결제 처리: 통일된 인터페이스를 통한 결제 진행
- 결과 처리: 성공/실패 결과를 표준화된 형태로 반환
사례 2: GUI 테마 시스템 구현 사례
시스템 구성
graph TB Client[애플리케이션 클라이언트] ThemeFactory[테마 팩토리 인터페이스] LightFactory[라이트 테마 팩토리] DarkFactory[다크 테마 팩토리] ButtonInterface[버튼 인터페이스] PanelInterface[패널 인터페이스] LightButton[라이트 버튼] LightPanel[라이트 패널] DarkButton[다크 버튼] DarkPanel[다크 패널] Client --> ThemeFactory ThemeFactory --> LightFactory ThemeFactory --> DarkFactory LightFactory --> LightButton LightFactory --> LightPanel DarkFactory --> DarkButton DarkFactory --> DarkPanel ButtonInterface --> LightButton ButtonInterface --> DarkButton PanelInterface --> LightPanel PanelInterface --> DarkPanel
Workflow
- 사용자 테마 선택: 사용자가 설정에서 라이트/다크 테마 선택
- 팩토리 결정: 설정값에 따라 적절한 테마 팩토리 선택
- UI 컴포넌트 생성: 선택된 팩토리를 통해 일관된 테마의 컴포넌트 생성
- 화면 렌더링: 생성된 컴포넌트들로 일관된 Look & Feel 의 UI 구성
Abstract Factory Pattern 의 역할
- 일관성 보장: 같은 테마 내의 모든 컴포넌트가 동일한 스타일 적용
- 테마 교체 용이성: 팩토리만 변경하면 전체 UI 테마 변경
- 확장성: 새로운 테마 추가 시 기존 코드 수정 불필요
패턴 유무에 따른 차이점
- 패턴 적용 시:
- 테마별 일관성 자동 보장
- 새 테마 추가 시 최소 코드 변경
- 컴포넌트간 호환성 문제 없음
- 패턴 미적용 시:
- 각 컴포넌트별로 개별 테마 관리 필요
- 테마 변경 시 모든 컴포넌트 코드 수정
- 컴포넌트간 스타일 불일치 위험
사례 3: 크로스 플랫폼 GUI 애플리케이션
온라인 상거래 플랫폼에서 Windows, macOS, Linux 를 지원하는 데스크톱 애플리케이션을 개발하는 경우
시스템 구성
graph TB subgraph "Client Application" A[Order Management UI] B[Product Catalog UI] C[Payment Processing UI] end subgraph "Abstract Factory Layer" D[UI Component Factory] end subgraph "Platform Factories" E[Windows Factory] F[macOS Factory] G[Linux Factory] end subgraph "Platform Components" H[Windows Button] I[Windows Dialog] J[macOS Button] K[macOS Dialog] L[Linux Button] M[Linux Dialog] end A --> D B --> D C --> D D --> E D --> F D --> G E --> H E --> I F --> J F --> K G --> L G --> M
Workflow
- 초기화 단계: 플랫폼 감지 후 적절한 팩토리 선택
- UI 구성 단계: Abstract Factory 를 통해 플랫폼별 컴포넌트 생성
- 이벤트 처리 단계: 공통 인터페이스를 통한 이벤트 처리
- 렌더링 단계: 플랫폼별 최적화된 렌더링 수행
Abstract Factory Pattern 의 역할
- 플랫폼 추상화: 각 플랫폼의 특성을 숨기고 통일된 인터페이스 제공
- 일관성 보장: 동일 플랫폼 내 모든 컴포넌트가 일관된 룩앤필 유지
- 확장성 제공: 새로운 플랫폼 추가 시 기존 코드 수정 최소화
패턴 유무에 따른 차이점
- 패턴 적용 전:
- 플랫폼별 조건문이 코드 전체에 산재
- 새 플랫폼 추가 시 모든 UI 코드 수정 필요
- 플랫폼 간 컴포넌트 호환성 문제 발생 가능
- 패턴 적용 후:
- 깔끔한 추상화로 플랫폼 독립적 코드 작성 가능
- 새 플랫폼 추가 시 팩토리 구현만으로 확장 가능
- 컴파일 타임에 호환성 검증으로 안정성 향상
구현 예시
Python
|
|
Javascript
|
|
Java
|
|
실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점
구분 | 항목 | 설명 | 권장사항 |
---|---|---|---|
설계 단계 | 제품군 정의 | 관련 객체들을 논리적으로 그룹화하고, 제품군 간 역할과 책임을 명확히 정의 | 도메인 전문가와 협업하여 실제 사용 케이스 기반 설계 |
인터페이스 안정성 | 추상 인터페이스는 자주 변경되지 않도록 최소 기능만 정의 | 확장 가능한 구조와 신중한 초기 설계 | |
복잡도 관리 | 과도한 추상화와 불필요한 클래스 생성은 오히려 유지보수 어려움으로 이어짐 | 필요 시에만 적용, 단순한 문제에는 단순한 해결책 | |
확장 계획 | 새로운 제품군 추가를 고려한 구조를 갖추지 않으면 변경이 전체에 영향을 미침 | 확장 포인트를 사전에 정의하거나 기본 구현 제공 | |
플랫폼/환경 다양성 | 다양한 OS, 클라우드, 테스트 환경 등에서의 적용 가능성 | DI 컨테이너 및 설정 기반 팩토리 선택 구조 활용 | |
구현 단계 | 인터페이스 설계 | 클래스 간 의존을 줄이고, 클라이언트는 추상 인터페이스만 알게 설계 | 구체 구현을 숨기고 인터페이스 중심 설계 |
팩토리 등록/선택 메커니즘 | 런타임 환경에 따라 다른 팩토리를 선택해야 하는 경우가 많음 | 설정 파일, 전략 패턴, FactoryProvider 활용 | |
예외 처리 | 잘못된 팩토리 인스턴스나 제품 생성 실패 시 적절한 핸들링 필요 | 검증 로직 추가 및 기본/디폴트 처리 제공 | |
클래스 수 증가 | 제품군/팩토리 수만큼 클래스 수 증가 → 유지보수 부담 가능 | 코드 생성기, 공통 로직 추출, 패키지 구조 체계화 | |
운영 단계 | 성능 최적화 | 무거운 객체나 빈번히 생성되는 객체의 경우 성능에 악영향 | 지연 초기화 (Lazy Initialization), 객체 풀링 적용 |
로깅 및 추적 | 어떤 팩토리/제품이 사용되었는지 운영 환경에서 확인이 어려울 수 있음 | 팩토리 사용 로그, 제품 생성 이벤트 추적 로깅 구현 | |
모니터링 | 팩토리 기반 시스템에서 성능 병목이나 메모리 누수가 발생할 수 있음 | 메모리/GC 프로파일링 도구, 팩토리별 사용량 수집 | |
테스트 단계 | 테스트 전략 | 제품 객체가 많고 상태가 다양한 경우 테스트 코드가 복잡해질 수 있음 | 인터페이스 기반 설계 + Mock 팩토리 분리 구현 |
DI 활용 | 테스트 환경에서 팩토리를 쉽게 바꿀 수 있어야 함 | DI 컨테이너/환경 프로파일 기반 객체 주입 | |
제품군별 격리 테스트 | 제품군 간 의존이나 혼용 시 버그 가능성 존재 | 제품군별 독립적인 테스트와 타입 검증 체계 설계 |
- 설계 시에는 제품군을 실제 도메인 기반으로 명확히 정의하고, 인터페이스 최소화에 집중해야 함.
- 구현 시에는 팩토리 등록/선택 로직과 예외 처리 로직을 구조화하고 클래스 수 증가에 유의해야 함.
- 운영 시에는 성능 최적화와 추적성 확보를 위한 로깅/모니터링 체계를 마련해야 함.
- 테스트 시에는 DI 기반 Mock 전략과 제품군 단위 테스트를 병행하는 구조가 권장됨.
관련 기술과 연계
기술 영역 | 연계 방식 | 설명 |
---|---|---|
Dependency Injection (DI) | Factory 주입 | Spring, Guice 등에서 팩토리를 DI 로 관리 가능 |
Configuration Management | 설정 기반 팩토리 선택 | 설정값에 따라 팩토리 동적 선택 (e.g. properties, YAML) |
Plugin Architecture | 팩토리 등록 방식 | 외부 모듈의 제품군을 플러그인 팩토리로 등록/로딩 |
GUI Toolkits | 테마별 제품군 제공 | 각 OS 별 버튼, 메뉴 등 GUI 컴포넌트를 팩토리로 구성 |
Abstract Factory 패턴 활용 시 흔한 실수
실수 | 설명 | 개선 방안 |
---|---|---|
팩토리 기능 과도 집중 | Factory 클래스에 논리 추가로 SRP 위반 | 팩토리는 오직 객체 생성만 담당 |
팩토리 간 결합 발생 | 팩토리 내부에서 다른 팩토리 직접 생성 | DI 또는 서비스 로케이터 패턴 적용 |
제품군 확장 시 인터페이스 확장 반복 | 인터페이스 변경이 연쇄 영향을 줌 | 인터페이스의 최소화를 유지, 여러 인터페이스로 분리 고려 |
팩토리 기능 과도 집중 (SRP 위반)
잘못된 예시
|
|
문제점: 팩토리가 객체 생성뿐 아니라 렌더링 로직까지 담당하며, 단일 책임 원칙 (SRP) 을 위반하고 있음.
개선된 예시
|
|
팩토리 간 결합 발생
잘못된 예시
📛 문제점: 팩토리 안에서 또 다른 팩토리를 직접 생성하고 있어, 결합도 증가 및 테스트 어려움 초래
개선된 예시 (DI 적용)
또는 서비스 로케이터 패턴 사용 예시:
|
|
제품군 확장 시 인터페이스 확장 반복
잘못된 예시
📛 문제점: 인터페이스 변경이 연쇄적으로 영향을 미쳐 기존 구현체까지 수정 필요
개선된 예시 (인터페이스 최소화 & 분리)
✅ 각 기능이 독립된 인터페이스로 구성되어 있어 제품군 확장 시 영향 최소화됨
테스트 전략
전략 | 설명 | 장점 |
---|---|---|
Mock 팩토리 사용 | 테스트 전용 팩토리 구현으로 실제 제품 대신 Mock 객체 생성 | 단위 테스트 간소화, 외부 의존 제거 |
DI 기반 팩토리 주입 | 팩토리를 외부에서 주입받아 테스트 시 원하는 객체 생성 | 테스트 유연성 향상, 의존성 제어 가능 |
팩토리 인터페이스 추상화 | 테스트 대상이 인터페이스만 참조 | 테스트 시 다양한 구현 객체로 대체 용이 |
리팩토링 전략
시나리오 | 전략 | 설명 |
---|---|---|
제품군이 많아짐 | 서브팩토리 분리 | 제품 계열별로 인터페이스를 나누고 소형 팩토리로 분리 |
생성 메서드 중복 증가 | 공통 로직 유틸리티화 | 생성 로직 공통화 또는 헬퍼 함수 추출 |
팩토리 중복 사용 | 싱글톤 패턴 적용 | 팩토리의 재사용성과 메모리 사용 최적화 |
팩토리 난립 | 팩토리 레지스트리 패턴 도입 | 팩토리들을 Map 등으로 관리하여 팩토리 폭주 방지 |
패턴 확장 적용 시 고려 사항
고려 항목 | 설명 | 주의점 |
---|---|---|
서비스 구성 전략 | 팩토리 기반으로 모듈 분리 가능 | 모듈 경계 명확히, 경합 상황 방지 |
제품군 확장 전략 | 기존 인터페이스 유지하면서 새로운 제품군 추가 | SRP 위반하지 않도록 인터페이스 분리 고려 |
상호 운용성 | 여러 제품군 조합의 인터페이스 통합 여부 판단 | 공통 추상화 계층 정의 필요 |
제품군 제거 전략 | 사용되지 않는 제품군 관리 | 의존도 파악 및 자동화 도구 활용 (e.g., 코드 커버리지 분석) |
최적화하기 위한 고려사항 및 주의점
구분 | 항목 | 설명 | 권장사항 | |
---|---|---|---|---|
설계 및 구현 | 인터페이스 설계 | 확장성 있는 구조로 설계되어야 하며, 불필요한 메서드 추가는 피해야 함 | 파라미터화된 팩토리 적용, 인터페이스 최소화 | |
팩토리 재사용 구조 | 팩토리를 반복 생성하면 성능 저하와 메모리 낭비 발생 | 싱글톤 또는 DI 컨테이너를 통한 공유 관리 | ||
코드 반복 최소화 | 제품군이 많을수록 유사 코드가 많아짐 | 제네릭, 템플릿, 코드 생성기 활용 | ||
실행 성능 | 지연 초기화 | 무거운 객체를 불필요하게 즉시 생성하면 응답 지연, 자원 낭비 초래 | 프록시 패턴과 결합한 Lazy Loading | |
객체 풀링 | 빈번히 재사용되는 객체는 매번 생성하지 않고 재사용 가능 | Object Pool 패턴 도입 | ||
조건 분기 최소화 | 팩토리 선택 로직이 많아질수록 if/switch 가 복잡해짐 | 맵 기반 룩업 테이블 적용 (Key → 팩토리) | ||
팩토리 캐싱 | 동일한 팩토리를 매번 생성하면 리소스 낭비 | 팩토리 인스턴스 캐시 저장 또는 DI 주입 | ||
메모리 관리 | 객체 수명 주기 관리 | 생성된 객체가 참조되지 않고 남아 있으면 GC 부하 및 누수 가능성 있음 | 약한 참조 (WeakRef), 명확한 범위 지정, 명시적 해제 | |
불필요 객체 생성 방지 | 모든 제품을 사전에 만들 경우 메모리 낭비 | 필요 시점에만 생성 (On-demand) | ||
GC/메모리 누수 대응 | 팩토리나 제품이 불필요하게 메모리에 남아 있으면 리소스 부족으로 이어질 수 있음 | 주기적 정리, 팩토리 수명주기 모니터링 | ||
확장성 | 런타임 팩토리 변경 | 동적 로딩, 설정 파일 기반으로 팩토리를 교체해야 할 수 있음 | Reflection, 플러그인 아키텍처, 전략 패턴 적용 | |
병렬 처리 지원 | 멀티스레드 환경에서는 상태 공유가 위험할 수 있음 | 불변 객체 사용, ThreadLocal 팩토리 활용 | ||
분산 시스템 대응 | 팩토리 인스턴스를 서비스 별로 분산해야 하는 요구 발생 | 서비스 레지스트리와 연계한 팩토리 분산 설계 | ||
유지보수 및 모니터링 | 사용 패턴 추적 및 성능 테스트 | 팩토리 변경이 전체 시스템 성능에 영향을 줄 수 있으므로 사전 검증과 추적 필요 | 팩토리 단위 성능 로깅, 사용 메트릭 수집 | |
클래스 증가 관리 | 제품/팩토리 수에 따라 클래스 수 급증 → 관리 부담 | 구조적 패키징, 코드 생성기 사용, 문서화 | ||
디버깅 및 테스트 용이성 | 테스트용 객체 생성이 어려울 수 있음 | Mock 팩토리 또는 테스트 전용 팩토리 도입 |
- 설계 단계에서는 인터페이스 최소화, 공통 로직 추출, 템플릿/제네릭 활용으로 코드 확장성과 단순성 확보.
- 성능 최적화는 지연 로딩, 객체 풀링, 캐싱을 기반으로, 런타임 리소스를 절약.
- 확장성과 병렬성을 위해 스레드 안전성과 동적 설정/로딩 전략을 고려.
- 운영/테스트 단계에서는 팩토리 모니터링, 성능 분석, Mock 구조 설계가 필수.
주제와 관련하여 주목할 내용
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
설계 원칙 및 아키텍처 | 객체 생성 원칙 | 생성 로직 캡슐화 | 객체 생성 책임 분리로 유연성과 재사용성 향상 |
DIP / OCP 적용 | 느슨한 결합 / 확장성 | 의존성 역전 및 확장 가능한 구조 설계 가능 | |
SRP 적용 | 단일 책임 부여 | 팩토리는 제품 생성에만 집중 | |
플랫폼 독립성 | 인터페이스 기반 설계 | 플랫폼에 의존하지 않는 구조 실현 가능 | |
레이어드 아키텍처 | 계층 기반 배치 | 팩토리를 계층별로 구성해 역할 분리 | |
디자인 일관성 | UI 구성요소 일관성 유지 | Theme 기반 UI 구성 시 효과적 | |
구현 전략 | 인터페이스 기반 | 추상 팩토리 | 제품군 생성 인터페이스 제공 |
클래스 기반 | 구체 팩토리 | 실제 객체 생성 로직 구현 | |
팩토리 셀렉터 | 런타임 팩토리 결정 | 조건 (운영체제, 지역 등) 에 따라 동적 선택 | |
DI 통합 | DI/IoC 자동 주입 | 프레임워크가 팩토리를 주입하여 관리 | |
제네릭 팩토리 | 타입 안전성 보장 | 컴파일 타임 타입 체크 가능 (Java, C# 등) | |
리플렉션 활용 | 런타임 동적 생성 | 팩토리를 리플렉션 기반으로 동적 구성 | |
성능 최적화 | Lazy Initialization | 지연 초기화 | 객체가 실제 필요할 때 생성 |
Object Pooling | 객체 재사용 | 비용이 큰 객체 재활용으로 메모리 절약 | |
Thread-safe Factory | 스레드 안전성 | 멀티스레드 환경에서 안전한 객체 생성 보장 | |
Async Factory | 비동기 팩토리 구현 | async/await , Future 기반 처리 | |
JIT 최적화 설계 | 인라인화 고려 | JIT 최적화를 고려한 팩토리 구성 | |
테스트 전략 | Mock Factory | 테스트용 객체 생성 | 테스트 대상 대체용 객체 구성 |
Test Doubles | Stub / Spy 등 | 다양한 유형의 테스트 더블 지원 | |
통합 테스트 전략 | 실환경 시뮬레이션 테스트 | 실제 제품군/팩토리 기반 테스트 수행 | |
현대적 응용 | 마이크로서비스 | Service Factory | 서비스 단위 객체를 생성하는 팩토리 |
클라우드 환경 | Provider Factory / Dynamic Loading | 클라우드 제공업체별 객체 생성 및 런타임 팩토리 로딩 | |
UI/UX | Theme Factory | 테마 기반 UI 요소 일관 생성 | |
디자인 시스템 | 컴포넌트 일관성 유지 | UI 구성요소 표준화 및 확장성 확보 | |
보안 | Secure Factory | 권한 기반 객체 생성 제어 | |
프레임워크 통합 | Spring,.NET 등 | DI 컨테이너와 팩토리 자동 연계 | |
프로그래밍 패러다임 | 함수형 프로그래밍 | 고차 함수 기반 팩토리 | 클로저와 커링을 활용한 팩토리 생성 |
리액티브 프로그래밍 | 스트림 기반 팩토리 | RxJava, Reactor 기반으로 구성 | |
불변성 | Immutable 객체 팩토리 | 불변 객체 생성을 위한 빌더 조합 | |
적용 사례 | GUI 컴포넌트 | 운영체제별 UI 구성 | OS 별 GUI 를 각각 생성 |
DB 연결 | DB 별 커넥션 객체 생성 | DB 종류에 따라 팩토리 분리 설계 | |
테스트 / 모킹 | Mock / Stub 팩토리 | 테스트 편의성을 위한 구조 | |
제품군 간 호환성 제어 | 제한된 조합만 허용 | 동일 제품군끼리만 상호작용 가능하게 설계 |
반드시 학습해야할 내용
핵심 개념 및 구조
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
기본 개념 | Abstract Factory | 객체군 생성 인터페이스 | 관련 제품군을 생성하기 위한 추상 인터페이스 |
Concrete Factory | 구체 팩토리 구현 | 특정 제품군을 실제로 생성하는 클래스 | |
Product Family | 제품군 개념 | 함께 사용되는 객체들의 논리적 집합 | |
Client | 클라이언트 역할 | 추상 인터페이스를 통해 객체를 생성하고 사용하는 코드 | |
Factory Method | 단일 제품군 생성 | Abstract Factory 의 하위/보완 패턴 | |
Builder | 복합 객체 생성 패턴 | 생성 과정 단계 분리, Abstract Factory 와 조합 가능 | |
Singleton | 인스턴스 제어 | 팩토리 인스턴스의 유일성 보장 | |
Factory Registry | 팩토리 관리 체계 | 다양한 팩토리를 중앙화하여 등록/선택 가능 |
객체지향 및 설계 원칙
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
객체지향 설계 | SOLID 원칙 | DIP, OCP 등 | 추상화, 확장성, 변경 최소화 등 핵심 설계 원칙 |
의존성 역전 / 의존성 주입 | DI, IoC | 추상화 중심 의존성 관리 방식 | |
인터페이스 설계 | 인터페이스 분리, 일관성 | 변경 최소화, 확장 용이성 확보 | |
느슨한 결합 & 높은 응집도 | 결합도/응집도 관리 | 클래스 간 의존성을 낮추고 내부 일관성을 높임 | |
리플렉션 | 동적 객체 생성 | 런타임 팩토리 생성/바인딩 전략에 활용 가능 |
구현 전략 및 최적화
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
객체 수명/리소스 | Lazy Initialization | 지연 초기화 | 필요한 시점에 객체를 생성하여 메모리 효율화 |
Object Pooling | 객체 재사용 | 비용 높은 객체에 대해 풀링 전략 적용 | |
동시성 환경 | Thread-Safe Factory | 스레드 안전성 보장 | 멀티스레드 환경에서 안전한 객체 생성 |
비동기 처리 | Async Factory | 비동기 생성 처리 | async/await , CompletableFuture 등 |
성능 최적화 | GC 최적화 | 가비지 컬렉션 이해 | 객체 수명 주기와 메모리 회수 전략 연계 |
테스트 및 품질 전략
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
테스트 전략 | Mock Factory | 테스트용 팩토리 구성 | 실제 객체 대신 사용할 가짜 객체 생성 |
Test Doubles | Stub, Spy, Fake 등 | 다양한 테스트 더블 유형 적용 | |
TDD 적용 전략 | 테스트 우선 개발 방식 | 팩토리 기반 객체 생성을 테스트 주도 방식으로 설계 | |
통합 테스트 | 실제 의존성 기반 테스트 | 팩토리 패턴을 통해 구성된 전체 시스템 테스트 |
패턴 조합 및 아키텍처 연계
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
패턴 연계 | Strategy Pattern | 런타임 팩토리 선택 전략 | 클라이언트에서 전략적으로 팩토리 선택 |
Composite Pattern | 제품 계층 구조 구현 | 제품군이 트리 구조일 때 조합 사용 | |
Prototype Pattern | 객체 복제 기반 생성 | 기존 객체 복사를 통한 새로운 제품 생성 | |
아키텍처 설계 | Layered Architecture | 계층화된 설계 구조 적용 | 추상 팩토리를 각 계층에 배치 가능 |
Plugin Architecture | 기능 확장 유연성 확보 | 팩토리를 플러그인 형태로 등록/교체 가능 | |
프레임워크 통합 | Spring, Guice,.NET Core | DI 기반 객체 생성 관리 | 프레임워크 DI 컨테이너와 팩토리 통합 |
플랫폼 전략 | Cross-platform | 클라이언트 코드 불변성 | 인터페이스 기반 구현으로 플랫폼 독립성 확보 |
학습 및 실무 고려사항
카테고리 | 주제 | 항목 | 설명 |
---|---|---|---|
설계 원칙 | 확장성 | 제품군 확장 방식 | 새로운 객체군을 쉽게 추가 가능해야 함 |
유지보수성 | 변경 최소화 전략 | 클라이언트 수정 없이 내부 확장 가능 | |
실무 비용 분석 | 초기 구현 비용 | 도입 전 분석 요소 | 클래스 수 증가, 설계 복잡도 고려 |
코드 복잡성 관리 | 모듈화 | 구성요소 수 관리 | 클래스/팩토리 수 증가를 분리/캡슐화로 관리 |
도구 활용 | 코드 생성기, 플러그인 | 자동 팩토리 생성 등 | 코드 템플릿/도구 활용으로 생산성 향상 |
용어 정리
카테고리 | 용어 | 설명 |
---|---|---|
패턴 구성요소 | Abstract Factory | 관련 제품군을 생성하기 위한 추상 인터페이스 또는 클래스 |
Concrete Factory | 특정 제품군 생성을 실제로 구현한 클래스 | |
Abstract Product | 제품군 내 객체들의 공통 인터페이스 | |
Concrete Product | 실제로 생성되는 구체 객체, Abstract Product 구현체 | |
Client | 추상 인터페이스를 통해 제품을 생성하고 사용하는 비즈니스 로직 주체 | |
Product Family | 함께 사용되도록 설계된 관련 객체들의 집합 (예: MacButton, MacCheckbox) | |
FactoryProducer / FactoryProvider | 조건에 따라 팩토리를 선택하거나 제공하는 클래스 또는 유틸 | |
Factory Method | 객체 생성을 캡슐화한 메서드, Abstract Factory 와 함께 사용 가능 | |
Builder | 복잡한 객체 생성을 위한 패턴, Abstract Factory 와 병행 사용 가능 | |
Singleton | 팩토리 인스턴스의 유일성 보장을 위한 보조 패턴 | |
설계 원칙 | DIP (Dependency Inversion Principle) | 고수준 모듈이 저수준 모듈에 의존하지 않고 추상화에 의존해야 한다는 원칙 |
OCP (Open/Closed Principle) | 소프트웨어 요소는 확장에는 열려 있고 변경에는 닫혀 있어야 함 | |
Loose Coupling (느슨한 결합) | 클래스 간 의존성을 줄이는 설계 방식 | |
High Cohesion (높은 응집도) | 모듈이나 클래스 내 구성 요소들이 밀접하게 관련된 상태 | |
Runtime Binding | 실행 시점에 실제 사용할 구체 팩토리나 제품을 결정하는 방식 | |
Cross-Platform | 다양한 플랫폼에서 공통 코드로 작동하는 소프트웨어 특성 | |
구현 및 기술 전략 | DI (Dependency Injection) | 외부에서 의존 객체를 주입받는 방식, 테스트 용이성 향상 |
Mock Object | 테스트 시 실제 객체를 대신하는 시뮬레이션 객체 | |
Factory Registry | 다양한 팩토리를 등록하고 관리하는 중앙 시스템 | |
Lazy Initialization | 객체가 필요할 때까지 생성을 지연하는 기법 | |
Service Locator | 런타임에 필요한 서비스를 찾아서 제공하는 구조 | |
SPI (Service Provider Interface) | 외부 모듈을 통해 팩토리 구현체를 교체할 수 있도록 하는 아키텍처 방식 | |
Prototype | 객체를 복제하여 새로운 인스턴스를 생성하는 패턴 | |
일반 개념/기초 용어 | Concrete Class | 추상 클래스나 인터페이스를 실제로 구현한 클래스 |
Polymorphism (다형성) | 동일한 인터페이스로 다양한 구현체를 사용할 수 있는 객체지향 특징 | |
GoF (Gang of Four) | 디자인 패턴 서적을 집필한 4 인의 저자 (Erich Gamma 외) | |
Creational Pattern (생성 패턴) | 객체 생성과 관련된 디자인 패턴의 분류군 (Abstract Factory, Builder 등 포함) |
참고 및 출처
- Refactoring Guru – Abstract Factory Pattern
- GeeksforGeeks – Abstract Factory Pattern in Java
- Baeldung – Java Factory & Abstract Factory Patterns
- Spring Framework – BeanFactory & IoC Container
- Microsoft – Dependency Injection in .NET
- Wikipedia – Abstract Factory Pattern