오늘 다뤄볼 주제는 팩토리 메소드 패턴입니다.
이 디자인의 특징은 클라이언트 코드 수준에서 객체를 직접 생성하지 않고, 팩토리 메소드에게 위임합니다.
이렇게 하면 클라이언트 코드와 사용하는 객체간의 거리를 만들어 유연성과 유지관리성을 높일 수 있게 되는데, 이런 표현을 책에서는 loose coupling(느슨한 결합)이라고 합니다.
아래 팩토리 메소드 패턴의 주요 구성요소와 함께 예제코드를 작성해보겠습니다
구성 요소
1) Generator = abstract class or interface
2) SubClass of Generator = Product 유형의 오브젝트를 생성할 팩토리 메소드가 구현될 클래스
3) Product = abstract class or interface
4) SubClass of Product = 팩토리 메소드에 의해 생성되는 오브젝트의 클래스
예제 코드 설명
- (1)Generator 는 팩토리 메소드가 구현될 추상화 클래스이며, ABC 클래스를 상속받아 Base 클래스의 메소드의 구현을 강제화 합니다
- (2) SubClass 는 Generator 클래스를 상속받아, 유형별 데이터 수집기 클래스의 객체를 생성하는 팩토리 메소드를 구현합니다.
- (3) Product 는 데이터 수집기의 추상화 클래스입니다.
- (4) SubClass 는 Product 클래스를 상속받아, 유형별 데이터 수집기의 동작을 구현합니다.
- (5) create_collector 함수는 유형별 데이터 수집기의 객체를 생성하는 팩토리 메소드를 구현합니다.
예제 코드
from abc import ABC, abstractmethod
class Collector(ABC):
@abstractmethod
def collect(self, data):
pass
class DBCollector(Collector):
def collect(self, data:str):
print(f"Collecting data from database: {data}")
class APICollector(Collector):
def collect(self, data:str):
print(f"Collecting data from API: {data}")
class Generator(ABC):
@abstractmethod
def generate(self):
pass
class DBCollectorGenerator(Generator):
def generate(self):
return DBCollector()
class APICollectorGenerator(Generator):
def generate(self):
return APICollector()
def create_collector(name:str):
generator = {
"db" : DBCollectorGenerator,
"api" : APICollectorGenerator
}
return generator[name]().generate()
def main():
db_collector = create_collector("db")
api_collector = create_collector("api")
target_data = ["user_information","product_information"]
for collecting_data in target_data:
db_collector.collect(collecting_data)
api_collector.collect(collecting_data)
if __name__ == "__main__":
main()
출력 결과
Collecting data from database: user_information
Collecting data from API: user_information
Collecting data from database: product_information
Collecting data from API: product_information
만약 제가 카카오 API 를 연동해서 어떤 데이터를 수집해야 하는 요구상황이 생긴다고 가정해볼게요.
저는 위 구조에서 KaKaoAPICollector 클래스를 추가하고 collect 메소드를 구현할거에요.
기존 코드의 영향을 적게 주면서 새로운 클래스만 추가하면 되기 때문에, 이런 부분에서 유연성과 확장성이 올라갔다고도 볼 수 있을 겁니다.
끝.