코드를 보다 보면 어떤 객체를 “언제”, “어떤 구현으로”, “무슨 조건에 따라” 생성해야 하는지가 점점 복잡해질 때가 있습니다. 이때 객체 생성 로직이 여기저기 흩어지면 코드가 빠르게 결합되기 쉽습니다. 팩토리 패턴은 이런 생성 책임을 다루는 대표적인 패턴입니다.
이 글에서는 아래 내용을 정리합니다.
- 팩토리 패턴이 무엇인지
- 왜 객체 생성 책임을 분리하는지
- 어떤 상황에서 잘 맞는지
- 전략 패턴이나 DIP와는 어떻게 연결되는지
핵심은 팩토리 패턴은 객체 사용 코드가 생성 세부사항까지 직접 알지 않도록 해서 결합도를 낮추는 생성 구조라는 점입니다.
팩토리 패턴이란 무엇인가
아주 단순하게 말하면:
- 객체를 직접
new하는 대신 - 별도의 생성 책임을 가진 곳에서 만들어 주는 방식
입니다.
즉, 사용하는 쪽은 “무엇이 필요한가”를 말하고, 실제 생성 세부사항은 팩토리가 맡는 구조입니다.
왜 생성 책임을 분리할까
객체를 직접 생성하기 시작하면:
- 구체 클래스 이름을 알아야 하고
- 생성 조건 분기가 늘어나며
- 초기화 규칙이 여러 곳에 흩어질 수 있습니다
반대로 팩토리로 모으면 생성 규칙을 한곳에 정리하기 쉬워집니다.
어떤 상황에서 잘 맞을까
- 생성 조건이 복잡할 때
- 환경에 따라 구현체가 달라질 때
- 생성 과정이 여러 단계를 가질 때
- 호출부에서 구체 구현을 덜 알고 싶을 때
즉, “생성 자체”가 의미 있는 설계 요소가 되기 시작하면 팩토리가 유용해집니다.
전략 패턴과는 어떻게 다를까
두 패턴은 종종 같이 등장하지만 역할이 다릅니다.
- 전략 패턴: 행동 교체 구조
- 팩토리 패턴: 생성 책임 분리 구조
즉, 팩토리가 전략 객체를 만들어 줄 수도 있습니다.
DIP와는 어떻게 연결될까
팩토리 패턴은 구체 구현을 생성 지점에 몰아두고, 나머지 코드는 더 추상에 의존하게 만들 수 있어서 DIP와 잘 연결됩니다.
즉:
- 사용 코드는 추상 역할만 알고
- 어떤 구현을 만들지는 팩토리가 책임지는 구조가 되기 쉽습니다.
자주 하는 오해
1. new를 쓰면 안 되니 무조건 팩토리를 써야 한다
그렇지는 않습니다. 생성이 단순한 곳까지 모두 팩토리로 감싸면 오히려 과할 수 있습니다.
2. 팩토리 패턴은 클래스 수만 늘린다
작은 코드에서는 그럴 수 있지만, 생성 규칙이 복잡할수록 오히려 훨씬 읽기 쉬워질 수 있습니다.
3. 팩토리 패턴은 프레임워크가 대신해주는 것이다
프레임워크가 도와줄 수는 있지만, 생성 책임을 어떻게 둘지는 여전히 설계 문제입니다.
간단한 예시
interface PaymentStrategy {
pay(amount: number): void;
}
class CardPayment implements PaymentStrategy {
pay(amount: number) {
console.log(`Card: ${amount}`);
}
}
class PointsPayment implements PaymentStrategy {
pay(amount: number) {
console.log(`Points: ${amount}`);
}
}
class PaymentFactory {
static create(method: 'card' | 'points'): PaymentStrategy {
if (method === 'card') return new CardPayment();
return new PointsPayment();
}
}
const strategy = PaymentFactory.create('card');
strategy.pay(100);
핵심은 생성 조건이 PaymentFactory에 모여 있어서 호출부가 구체 클래스 이름을 덜 알게 된다는 점입니다.
FAQ
Q. 입문자는 어디서 팩토리를 써보면 좋을까
조건에 따라 다른 구현체를 만드는 코드부터 시작하면 좋습니다.
Q. 팩토리와 DI는 같은가
같지는 않습니다. 다만 둘 다 생성과 의존성 연결을 다룬다는 점에서 자주 함께 나옵니다.
Q. 생성이 단순한데도 팩토리가 필요할까
항상 그렇지는 않습니다. 생성 규칙이 의미 있게 복잡해질 때 더 유용합니다.
Read Next
- 행동 구조는 전략 패턴 가이드와 잘 이어집니다.
- 의존성 연결은 의존성 주입 가이드와 같이 보면 좋습니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.