# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # 第三章 Factory Pattern
#
# 從文字上面解釋，就是想成工廠產生不同物件那樣，我今天只要根據不同參數就可以產生不同物件！ 那麼書中提到Factory pattern的三種變形
#
#  - Simple Factory Pattern
#  - Factory method Pattern
#  - Abstract Factory Pattern
#  
# 其實第一個跟第二個感覺是沒什麼差別的...精髓都一樣是經由參數來生成不同物件！ 下面就是一個簡單的示範藉由參數來建立不同物件！

# +
from abc import ABCMeta, abstractmethod

class Insect(metaclass=ABCMeta):
    
    @abstractmethod
    def intro(self):
        raise NotImplementedError
    
class Bug(Insect):
    
    def intro(self):
        print("I'm bug")
        
def createInsect(name):
    cls = globals()[name]
    return cls()
    
bug = createInsect('Bug')
bug.intro()


# -

# 至於**Abstract Factory Pattern**，書中舉的例子老實講，我並沒有特別的感受，倒不如說我只覺得不就是定義共同interface而已嗎？ 以下來看看書中例子

# +

class PizzaFactory(metaclass=ABCMeta):
    
    @abstractmethod
    def createVegPizza(self):
        pass
    
    @abstractmethod
    def createNonVegPizza(self):
        pass
    
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()

# 這邊定義了pizza工廠應該要有的interface就是做素跟非素兩種pizza

class VegPizza(metaclass=ABCMeta):
    
    @abstractmethod
    def prepare(self, VegPizza):
        pass

    
class NonVegPizza(metaclass=ABCMeta):
    @abstractmethod
    def serve(self, VegPizza):
        pass
    
    
class DeluxVeggiePizza(VegPizza):
    def prepare(self):
        print("Prepare ", type(self).__name__)
        
class ChickenPizza(NonVegPizza):
    def serve(self, VegPizza):
        print(type(self).__name__, " is served with Chicken on ", type(VegPizza).__name__)
        
class MexicanVegPizza(VegPizza):
    def prepare(self):
        print("Prepare ", type(self).__name__)
        
class HamPizza(NonVegPizza):
    def serve(self, VegPizza):
        print(type(self).__name__, " is served with Ham on ", type(VegPizza).__name__)

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

# 上面就是書中舉的例子，老實講就是定義interface，去繼承實作他而已.. 這章節感覺比較沒什麼需要特別記錄的。

StarcoderdataJupyterScriptsDedupFiltered