반응형

정의

the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. 

-- 영어 위키백과

Factory method는 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며. 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.

-- 한국어 위키백과

 

이런식으로 정의만 보면 절대 이해가 안간다.

바로 예시로 들어가보자.

 

일단 피자가게 사장님이 되었다고 해보자.

1.햄머슈룸 피자

2. 디럭스피자

3. 해산물 피자를 메뉴로 준비하였다.

 

class HamAndMushroomPizza():
    def __init__(self):
        self.__price = 8.50
        
    def put_toping(self):
    	self.topping = "HAM"

class DeluxePizza():
    def __init__(self):
        self.__price = 10.50
        
    def add_toping(self):
    	self.topping = "meat"

class SeafoodPizza():
    def __init__(self):
        self.__price = 11.50
    
    def add_toping(self):
    	self.topping = "meat"
        
    def add_cheese_crust(self):
    	self.cheese_crust = True

 

만약 이렇게 될시에, 소비자가 주문하려고 할때, 각각의 객체생성 방법에 대해 알고 있어야한다.

ham_mushroom_pizza = HamAndMushroomPizza()
delux_pizza = DeluxePizza()
seafood_pizza = SeafoodPizza()

 

이때, pizzaFactory를 하나 만들어준다면 어떻게 될까?

class PizzaFactory: 
    "The Factory Class"

    @staticmethod
    def create_pizza(pizza_type: str):
        if pizza_type == 'HAM_MUSHROOM_PIZZA_TYPE':
            return HamAndMushroomPizza()
        if pizza_type == 'DELUXE_PIZZA_TYPE':
            return DeluxePizza()
        if pizza_type == 'SEAFOOD_PIZZA_TYPE':
            return SeafoodPizza()
        return None


pizza = PizzaFactory().create_pizza("HAM_MUSHROOM_PIZZA_TYPE")

pizza.put_toping()

소비자는 피자 팩토리만 알면, 복잡한 객체생성방법에 대해 알 필요가 없게된다.

지금 예시는 간단해서 필요성을 못느낄수도 있지만,

각 피자에 따라 직접 토핑을 집어넣어줘야 피자가 생성됐다면?

팩토리라는 클라스의 필요성을 느낄수 있을 것이다.

 

 

이렇게만 바뀌면 객체지향적이라고 할 수 있을까?

SOLID원칙중 open/close원칙에 비추어 확인해보도록 하자.

 

 

class PizzaFactory: 
    "The Factory Class"

    @staticmethod
    def create_pizza(pizza_type: str):
        if pizza_type == 'HAM_MUSHROOM_PIZZA_TYPE':
            return HamAndMushroomPizza()
        if pizza_type == 'DELUXE_PIZZA_TYPE':
            return DeluxePizza()
        if pizza_type == 'SEAFOOD_PIZZA_TYPE':
            return SeafoodPizza()
        return None


pizza = PizzaFactory().create_pizza("SEAFOOD_PIZZA")

pizza.put_toping()

앞선 코드에서 피자종류만, 해산물피자로 바꾸었다.

그런데 에러가 날 것이다.

왜냐하면, SEAFOOD피자에서는 put_toping이 아니라 add_toping이기 때문이다.

 

이는 즉, 만약 HAM_MUSHROOM_PIZZA를 먼저만들고, SEAFOOD 피자로 확장했다고 했을떄,

확장을 했을때 코드를 수정해야한느 일이 발생한 것이다.

즉, 확장에 열려있고, 수정에 닫혀있어야한다는 open/closed principle에 어긋난다.

 

그러면 어떻게 해줘야할까?

class Pizza(ABCMeta):
    def __init__(self):
        self.__price = None
	
    @abstractmethod
    def add_toping(self):
    	pass


class HamAndMushroomPizza(Pizza):
    def __init__(self):
        self.__price = 8.50

    def add_toping(self):
	self.topping = "HAM"


class DeluxePizza(Pizza):
    def __init__(self):
        self.__price = 10.50

    def add_toping(self):
	self.topping = "MEAT"
        
        
class SeafoodPizza(Pizza):
    def __init__(self):
        self.__price = 11.50
        
       
    def add_toping(self):
	self.topping = "SEAFOOD"        
        
        
    def add_cheese_crust(self):
    	self.cheese_crust = True

 이런식으로 추상화된 클라스를 만들어줘서 통일감있게 강제해줘야한다.

이렇게 추상화된 클라스를 상속받기만 하면, 기존코드 수정 없이, 새로운 피자를 만들어낼 수 있다.(확장)

 

이는 또한 생성이라는 역할을 factory가 다 맡고 있다는 점에서 단일책임 원칙을 지키고 있다고 볼 수 있다.

반응형

+ Recent posts