개발블로그

[디자인패턴] 팩토리 패턴 본문

STUDY/CS

[디자인패턴] 팩토리 패턴

devmel 2026. 9. 4. 11:30
Contents 접기
 

개념

 

필요성

프로그램을 만들다 보면 객체를 생성하는 조건이 복잡해지는 경우가 있음.

 

ex) 결제 방식에 따라 서로 다른 결제 객체를 만들어야 함

if payment_type == "card":
    payment = CardPayment()
elif payment_type == "kakao":
    payment = KakaoPayPayment()
elif payment_type == "point":
    payment = PointPayment()

 

처음에는 이 정도 조건문도 크게 문제되지 않음. 

하지만 결제 방식이 계속 추가되거나, 객체 생성에 필요한 설정이 많아지면 생성 코드가 점점 복잡해짐

, 문제는 이런 생성 코드가 여러 곳에 흩어질 수 있다. 

=> 새로운 결제 방식이 추가될 때 여러 코드를 함께 수정해야 함.

 

팩토리 패턴은 이런 상황에서 사용 할 수 잇음

" 객체를 사용하는 코드가 객체 생성 조건까지 모두 알아야 할까? "

=> 객체를 생성하는 책임을 별도의 객체나 메서드로 분리해서, 사용하는 쪽이 생성 과정을 직접 알지 않아도 되게 만드는 패턴

 

 

의미

객체 생성 책임을 별도의 역할로 분리하는 패턴

=> 객체를 사용하는 코드는 어떤 객체가 필요한지만 요청하고, 실제로 어떤 클래스를 생성할지는 팩토리가 결정

즉, 객체 생성 책임을 한 곳으로 모아, 사용하는 코드가 생성 과정에 덜 의존하게 만드는 것.

사용하는 코드 - 객체를 요청하고 사용

팩토리 - 조건에 맞는 객체를 생성

생성되는 객체 - 실제 기능을 수행 

 

ex) 

# 주문 서비스는 결제 객체를 직접 만들지 않고, 팩토리에게 요청할 수 있음
payment = PaymentFactory.create(payment_type)
payment.pay(10000)

# 주문 서비스가 CardPayment, KakaoPayPayment, PointPayment를 직접 생성하지 않는다.
# 어떤 결제 객체를 만들지는 PaymentFactory가 담당

 

 

핵심 구조

구성 요소 역할 예시
Product 생성될 객체의 공통 형태 결제 수단
Concrete Product 실제로 생성되는 구체 객체 카드 결제, 카카오페이 결제, 포인트 결제
Factory 객체 생성 책임을 담당 결제 팩토리

 

 

적합

  • 객체 생성 조건이 여러개이다
  • 객체 생성 코드가 여러 곳에 반복된다
  • 생성 과정이 복잡하거나 자주 바뀐다
  • 사용하는 코드가 구체 클래스를 직접 알지 않게 만들고 싶다.

 

 


 

예시

 

EX] 

결제 방식에 따라 다른 결제 객체를 만들어야 할 때 

처음에는 필요한 곳에서 직접 객체를 생성할 수 있음

def order(payment_type, amount):
    if payment_type == "card":
        payment = CardPayment()
    elif payment_type == "kakao":
        payment = KakaoPayPayment()
    elif payment_type == "point":
        payment = PointPayment()
    else:
        raise ValueError("지원하지 않는 결제 방식입니다.")

    return payment.pay(amount)

 

같은 생성 로직이 여러 곳에서 필요해지면 문제가 생김

def refund(payment_type, amount):
    if payment_type == "card":
        payment = CardPayment()
    elif payment_type == "kakao":
        payment = KakaoPayPayment()
    elif payment_type == "point":
        payment = PointPayment()
    else:
        raise ValueError("지원하지 않는 결제 방식입니다.")

    return payment.refund(amount)

order()와 refund()는 목적이 다르지만, 결제 객체를 생성하는 조건문의 거의 같음. 

여기에 새로운 결제 방식이 추가된다면

elif payment_type == "naver":
    payment = NaverPayPayment()

이 코드를 order(), refund()처럼 결제 객체를 생성하는 모든 위치에 추가해야 함.

 

아래와 같은 문제들이 생긴다


문제 설명
중복 증가 같은 생성 조건문이 여러 함수에 반복된다.
수정 범위 증가 결제 방식이 추가될 때 여러 위치를 수정해야 한다.
누락 가능성 어떤 함수에는 새 결제 방식을 추가하지 않을 수 있다.
책임 혼합 주문/환불 로직이 결제 객체 생성 조건까지 알고 있다.

 

해결 : 팩토리로 생성 책임 분리하기

=>객체 생성 조건을 한곳으로 모으기

 

먼저 결제 객체들이 공통으로 제공할 동작을 정한다

class Payment:
    def pay(self, amount):
        pass

    def refund(self, amount):
        pass

 

이제 각 결제 방식을 구현함

class CardPayment(Payment):
    def pay(self, amount):
        return "카드 결제"

    def refund(self, amount):
        return "카드 환불"

class KakaoPayPayment(Payment):
    def pay(self, amount):
        return "카카오페이 결제"

    def refund(self, amount):
        return "카카오페이 환불"

class PointPayment(Payment):
    def pay(self, amount):
        return "포인트 결제"

    def refund(self, amount):
        return "포인트 환불"

 

그리고 객체 생성 책임을 PaymentFactory로 분리함

class PaymentFactory:
    @staticmethod
    def create(payment_type):
        if payment_type == "card":
            return CardPayment()
        elif payment_type == "kakao":
            return KakaoPayPayment()
        elif payment_type == "point":
            return PointPayment()

        raise ValueError("지원하지 않는 결제 방식입니다.")

 

이제 주문 로직과 환불 로직은 직접 결제 객체를 생성하지 않는다

def order(payment_type, amount):
    payment = PaymentFactory.create(payment_type)
    return payment.pay(amount)

def refund(payment_type, amount):
    payment = PaymentFactory.create(payment_type)
    return payment.refund(amount)

 

이 구조에서는 결제 객체를 생성하는 조건이 PaymentFactory 안에 모임

 

새로운 결제 방식이 추가되면 팩토리와 새로운 결제 클래스만 추가하면 됨

class NaverPayPayment(Payment):
    def pay(self, amount):
        return "네이버페이 결제"

    def refund(self, amount):
        return "네이버페이 환불"
class PaymentFactory:
    @staticmethod
    def create(payment_type):
        if payment_type == "card":
            return CardPayment()
        elif payment_type == "kakao":
            return KakaoPayPayment()
        elif payment_type == "point":
            return PointPayment()
        elif payment_type == "naver":
            return NaverPayPayment()

        raise ValueError("지원하지 않는 결제 방식입니다.")

 

order()와 refund()는 수정하지 않아도 됨. 


구분 역할
order(), refund() 결제 객체를 사용한다.
PaymentFactory 결제 객체를 생성한다.
CardPayment, KakaoPayPayment, PointPayment 실제 결제/환불 동작을 수행한다.

 

 

 

 


 

장점

장점

장점 설명
생성 책임 분리 객체를 사용하는 코드와 생성하는 코드를 분리할 수 있다.
중복 감소 여러 곳에 반복되던 생성 조건문을 한곳으로 모을 수 있다.
변경 범위 축소 생성 방식이 바뀌어도 사용하는 코드의 수정을 줄일 수 있다.
구체 클래스 의존 감소 사용하는 코드가 특정 클래스 생성 방식에 덜 의존하게 된다.
생성 과정 캡슐화 객체 생성에 필요한 복잡한 설정이나 조건을 팩토리 안에 숨길 수 있다.

 

 

효과적인 상황

상황 이유
생성 조건이 여러 개인 경우 조건을 팩토리 안에서 관리할 수 있다.
같은 생성 로직이 여러 곳에 반복되는 경우 중복된 생성 코드를 줄일 수 있다.
객체 생성 과정이 복잡한 경우 필요한 설정, 초기화, 의존성 연결을 팩토리 안에 모을 수 있다.
사용하는 코드가 구체 클래스를 몰라도 되는 경우 공통 인터페이스나 역할에 의존하도록 만들 수 있다.

 

 

 


 

주의점

 

단순히 클래스 하나를 생성하는 코드라면 팩토리를 만드는 것이 오히려 불필요할 구조가 될 수 있음.

 

질문 의미
객체 생성 조건이 여러 개인가? 팩토리로 분리할 이유가 있는지 확인한다.
같은 생성 코드가 여러 곳에 반복되는가? 중복 제거 효과가 있는지 확인한다.
생성 과정이 복잡한가? 초기화, 설정, 의존성 연결을 숨길 필요가 있는지 본다.
사용하는 코드가 구체 클래스를 몰라도 되는가? 생성 책임을 분리했을 때 의존성이 줄어드는지 확인한다.
팩토리가 너무 많은 조건을 떠안고 있지는 않은가? 팩토리 자체가 복잡해지는지 점검한다.