개발언어/PYTHON

[Python] 팩토리 메서드 패턴이란?

to,min 2024. 11. 10. 21:54

 

알게 모르게 개발 간 자주 사용하는 패턴이지만, 단어와 매칭이 안되거나 개념을 정리해 보려는 분들이 참고하면 좋을 것 같다.

 

팩토리 패턴이란?

객체의 생성 과정을 클라이언트 코드로부터 분리하여, 구체적인 클래스에 대한 의존성을 줄이고 확장성을 높이기 위해 객체 생성에 대한 책임을 팩토리로 넘기는 설계 패턴입니다. 이 패턴을 사용하면 클라이언트는 객체의 구체적인 생성 방식을 몰라도 객체를 사용할 수 있습니다

 

와닿지 않는 말들 같다... 간단히 말하자면 객체 생성의 책임을 별도의 팩토리 메서드나 팩토리 클래스로 분리하여 관리하는 것이다

코드로 보는게 더 직관적이니, 예시 코드를 첨부해 보겠다.

 

 

아래 코드는 팩토리 메서드 패턴을 사용하지 않는 코드이다.

클라이언트 쪽에서 내부 코드를 어느 정도 파악하고 별개 객체를 생성하여 사용하는 것을 볼 수 있다.

이에 따라 다양한 처리를 클라이언트에서 책임지게 된다.

from abc import ABC, abstractmethod

class Car(ABC):
    @abstractmethod
    def drive(self):
        pass
        
class Sedan(Car):
    def drive(self):
        print("drive car")
        
class SuperCar(Car):
    def drive(self):
        print("drive super car")
        

"""
## 호출 부분이라고 가정
팩토리 패턴을 사용하지 않은 코드를 호출한다면, 아래 처럼 호출부에 처리 로직이 들어가는 경우가
생길 수 있다.
"""
class Client():
    def __init__(self, car_type):
        if car_type == "sedan":
            self.car = Sedan()
        elif car_type == "supercar":
            self.car = SuperCar()
        else:
            print("error")
        
    def drive(self):
        self.car.drive()

client_ = Client("sedan")
client_2 = Client("supercar")

client_.drive()
client_2.drive()

 

 

아래는 팩토리 메서드 패턴을 적용한 코드이다.

클라이언트의 책임은 줄어들고, 클래스를 선언한 부분 또한 확장성이 용이하다. 새로운 Car type 이 추가되어도 Factories 만 추가하면 된다.

from abc import ABC, abstractmethod

class Car(ABC):
    @abstractmethod
    def drive(self):
        pass
        
class Sedan(Car):
    def drive(self):
        print("drive car")
        
class SuperCar(Car):
    def drive(self):
        print("drive super car")
        
"""
# 모두 동일한 Sedan 및 SuperCar 를 참조하게 됨 --> 각 차종 별 Factory 를 만들고
return 하는 구조로 변경 가능.
이번 코드는 간단한 정적 팩토리 패턴만 적용 
"""
class CarFactoryManager(): 
    factories = {
        "sedan": Sedan(),
        "supercar": SuperCar(),
    }

    @staticmethod
    def buyCar(car_type):
        return CarFactoryManager.factories.get(car_type)
        


"""
## 호출 부분이라고 가정
팩토리 패턴을 이용하여 클래스를 구성하거나, 공통 라이브러리 등을 구현한다고 한다면
아래처럼 클라이언트 들 즉 해당 클래스나 lib 를 사용하는 곳들에서 내부적으로 어떤식으로 구현되었는지
혹은 예외처리 등 절차가 간소화된다.  
"""
class Client():
    def __init__(self, car_type):
        self.car = CarFactoryManager.buyCar(car_type)
    
    def drive(self):
        self.car.drive()

client_sedan = Client("sedan")
client_superCar = Client("supercar")


client_sedan.drive()
client_superCar.drive()

 

 

주로 사용되는 팩토리 메서드가 적용된 코드

가장 자주 사용되는 건 아무래도 logging 모듈이지 않을까 싶다. 로깅 모듈은 팩토리메서드 패턴과 더불어 싱글톤 패턴도 적용된 코드이다

import logging
logger = logging.getLogger("test1")
print(logger)
logger = logging.getLogger("test2")
print(logger)