나는 이렇게 본다/파이썬 디자인 패턴

팩토리 메소드, 추상 팩토리 패턴

daco2020 2022. 5. 30. 19:44
반응형

팩토리 메소드 패턴

  • 인터페이스를 통해 객체를 생성하지만 팩토리가 아닌 서브 클래스가 해당 객체 생성을 위해 어떤 클래스를 호출할지 결정한다.
  • 팩토리 메소드는 인스턴스화가 아닌 상속을 통해 객체를 생성한다.
  • 팩토리 메소드 디자인은 유동적이다. 특정 객체가 아닌 같은 인스턴스나 서브 클래스 객체를 반환할 수 있다.
  • 팩토리 메소드 패턴은 객체를 생성하는 인터페이스를 정의하고 어떤 클래스를 초기화할지는서브 클래스의 결정에 맡긴다.

 

팩토리 메소드 구현 예

  • 커리어 서비스(링크드인)과 앨범 서비스(페이스북)가 개별적으로 존재한다.
  • 두 서비스는 공통적으로 개인 정보를 입력해야한다.
  • 서비스 종류에 따라 알맞는 내용을 포함하는 프로필을 생성해보자
from abc import abstractmethod

# Product 인터페이스
# Section 추상 클래스
class Section:
    @abstractmethod
    def describe(self):
        pass

# ConcreateProduct 클래스
class PersonalSection(Section):
    def describe(self):
        return "개인정보"

class AlbumSection(Section):
    def describe(self):
        return "앨범"

class CareerSection(Section):
    def describe(self):
        return "커리어"

# Creator 추상 클래스
class Profile:
    def __init__(self):
        self.sections = []
        self.createProfile() # profile 인스턴스 생성과 동시에 메서드를 실행시킨다.

    @abstractmethod
    def createProfile(self):
        pass

    def getSections(self):
        return self.sections

    def addSections(self, section):
        self.sections.append(section)

# ConcreateCreator 클래스
class linkedin(Profile):
    def createProfile(self): # 해당하는 Section을 sections에 담는다.
        self.addSections(PersonalSection())
        self.addSections(CareerSection())

class facebook(Profile):
    def createProfile(self):
        self.addSections(PersonalSection())
        self.addSections(AlbumSection())

# Creator 클래스를 호출하는 클라이언트
if __name__ == '__main__':
    profile_type = input("어떤 프로필을 만드시겠습니까? [LinkedIn or FaceBook]")
    profile = eval(profile_type.lower())()
    print("생성한 프로필", type(profile).__name__)
    print("프로필에 포함된 섹션 ::", [section.describe() for section in profile.getSections()])
# 결과1.
어떤 프로필을 만드시겠습니까? [LinkedIn or FaceBook]linkedin
생성한 프로필 linkedin
프로필에 포함된 섹션 :: ['개인정보', '커리어']

# 결과2.
어떤 프로필을 만드시겠습니까? [LinkedIn or FaceBook]facebook
생성한 프로필 facebook
프로필에 포함된 섹션 :: ['개인정보', '앨범']

 

팩토리 메소드 패턴의 장점

  • 유연성과 포괄성을 갖추며 한 클래스에 종속되지 않는다. ConcreateProduct가 아닌 인터페이스(Product)에 의존한다.
  • 객체를 생성하는 코드와 활용하는 코드를 분리해 의존성이 줄어든다. 클라이언트는 인자나 어떤 클래스가 생성되는지 알 필요가 없다.
  • 새로운 클래스 추가 등 유지보수가 쉽다.

 

추가 레퍼런스

 

[Design Pattern] 팩토리 메서드 패턴이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

팩토리 메소드 패턴 (Factory Method Pattern)

객체를 생성하기 위한 인터페이스를 정의하고, 인스턴스 생성은 서브클래스가 결정하게 한다

johngrib.github.io

 


 

추상 팩토리 패턴

  • 관련된 객체 집단을 생성하기 위해 한 개 이상의 팩토리 메소드가 필요
  • 다른 클래스 객체를 생성하기 위해 컴포지션을 사용
  • 관련된 객체 집단을 생성

 

추상 팩토리 구현 예

  • 인도식 피자와 미국식 피자를 판매하는 가게
  • 채식 피자와 일반 피자를 주문할 수 있음
from abc import abstractmethod

# AbstractFactory
class PizzaFactory:
    @abstractmethod
    def createVegPizza(self):
        pass

    @abstractmethod
    def createNonVegPizza(self):
        pass

# ConcreateFactory
class IndianPizzaFactory(PizzaFactory):
    def createVegPizza(self):
        return DeluxVeggiePizza()

    def createNonVegPizza(self):
        return ChickenPizza()

class USPizzaFactory(PizzaFactory):
    def createVegPizza(self):
        return MexicanVegPizza()

    def createNonVegPizza(self):
        return HamPizza()

# AbstractPorduct
class VegPizza:
    @abstractmethod
    def prepare(self, VegPizza):
        pass

class NonVegPizza:
    @abstractmethod
    def serve(self, VegPizza):
        pass

# ConcreateProducts
class DeluxVeggiePizza(VegPizza):
    def prepare(self):
        print(f"{type(self).__name__} 를 준비합니다.")

class ChickenPizza(NonVegPizza):
    def serve(self, VegPizza):
        print(f"{type(self).__name__} 는 {type(VegPizza).__name__} 에 치킨을 추가합니다.")

class MexicanVegPizza(VegPizza):
    def prepare(self):
        print(f"{type(self).__name__} 를 준비합니다.")

class HamPizza(NonVegPizza):
    def serve(self, VegPizza):
        print(f"{type(self).__name__} 는 {type(VegPizza).__name__} 에 햄을 추가합니다.")

# 실행 클래스
class PizzaStore:
    def __init__(self):
        pass

    def makePizzas(self):
        for factory in [IndianPizzaFactory(), USPizzaFactory()]:
            self.factory = factory
            self.NonVegPizza = self.factory.createNonVegPizza()
            self.VegPizza = self.factory.createVegPizza()
            self.VegPizza.prepare()
            self.NonVegPizza.serve(self.VegPizza)
        
pizza = PizzaStore()
pizza.makePizzas()

"""
# 결과.
DeluxVeggiePizza 를 준비합니다.
ChickenPizza 는 DeluxVeggiePizza 에 치킨을 추가합니다.
MexicanVegPizza 를 준비합니다.
HamPizza 는 MexicanVegPizza 에 햄을 추가합니다.
"""

 

추가 레퍼런스

 

[Design Pattern] 추상 팩토리 패턴이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

추상 팩토리 패턴 (Abstract Factory Pattern)

서로 관련성이 있는 다양한 객체를 생성하기 위한 인터페이스를 제공한다

johngrib.github.io

 

반응형