The Factory Method Pattern defines an interface for creating an object, but lets subclasses
decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Design Principle
Dependency Inversion Principle: high-level components should not depend on our low-level components; rather,
they should both depend on abstractions. Depend upon abstractions. Do not depend on concrete classes.
Best practices
By placing all creation code in one object or method, we avoid duplication in the code and provide
one place for maintenance.
Clients depend only upon interfaces reather than the concrete classes required to instantiate
objects => Allow to program to an interface, not an implementation => make the code more flexible
and extensible in the future.
fromabcimportABC,abstractmethod# Abstract ProductclassPizza(ABC):def__init__(self):self.name=""self.dough=""self.sauce=""self.toppings=[]defprepare(self):print(f"Preparing {self.name}")print(f"Tossing {self.dough}")print(f"Adding {self.sauce}")print("Adding toppings:")fortoppinginself.toppings:print(f" {topping}")@staticmethoddefbake():print("Bake for 25 minutes at 350")@staticmethoddefcut():print("Cutting the pizza into diagonal slices")@staticmethoddefbox():print("Place pizza in official PizzaStore box")# Concrete ProductsclassNYStyleCheesePizza(Pizza):def__init__(self):super().__init__()self.name="NY Style Sauce and Cheese Pizza"self.dough="Thin Crust Dough"self.sauce="Marinara Sauce"self.toppings.append("Grated Reggiano Cheese")classChicagoStyleCheesePizza(Pizza):def__init__(self):super().__init__()self.name="Chicago Style Deep Dish Cheese Pizza"self.dough="Extra Thick Crust Dough"self.sauce="Plum Tomato Sauce"self.toppings.append("Shredded Mozzarella Cheese")@staticmethoddefcut():print("Cutting the pizza into square slices")# Abstract CreatorclassPizzaStore(ABC):@abstractmethoddefcreate_pizza(self,item):passdeforder_pizza(self,pizza_type):pizza=self.create_pizza(pizza_type)print(f"--- Making a {pizza.name} ---")pizza.prepare()pizza.bake()pizza.cut()pizza.box()returnpizza# Concrete CreatorsclassNYPizzaStore(PizzaStore):defcreate_pizza(self,item):ifitem=="cheese":returnNYStyleCheesePizza()# Add other pizza types hereelse:returnNoneclassChicagoPizzaStore(PizzaStore):defcreate_pizza(self,item):ifitem=="cheese":returnChicagoStyleCheesePizza()# Add other pizza types hereelse:returnNone# Client codeif__name__=="__main__":ny_store=NYPizzaStore()chicago_store=ChicagoPizzaStore()ny_pizza=ny_store.order_pizza("cheese")print(f"Ethan ordered a {ny_pizza.name}\n")chicago_pizza=chicago_store.order_pizza("cheese")print(f"Joel ordered a {chicago_pizza.name}\n")"""Output:--- Making a NY Style Sauce and Cheese Pizza ---Preparing NY Style Sauce and Cheese PizzaTossing Thin Crust DoughAdding Marinara SauceAdding toppings: Grated Reggiano CheeseBake for 25 minutes at 350Cutting the pizza into diagonal slicesPlace pizza in official PizzaStore boxEthan ordered a NY Style Sauce and Cheese Pizza--- Making a Chicago Style Deep Dish Cheese Pizza ---Preparing Chicago Style Deep Dish Cheese PizzaTossing Extra Thick Crust DoughAdding Plum Tomato SauceAdding toppings: Shredded Mozzarella CheeseBake for 25 minutes at 350Cutting the pizza into square slicesPlace pizza in official PizzaStore boxJoel ordered a Chicago Style Deep Dish Cheese Pizza"""
packagemainimport"fmt"// Pizza interfacetypePizzainterface{Prepare()Bake()Cut()Box()GetName()string}// BasePizza structtypeBasePizzastruct{namestringdoughstringsaucestringtoppings[]string}func(b*BasePizza)Prepare(){fmt.Printf("Preparing %s\n",b.name)fmt.Printf("Tossing %s\n",b.dough)fmt.Printf("Adding %s\n",b.sauce)fmt.Println("Adding toppings:")for_,topping:=rangeb.toppings{fmt.Printf(" %s\n",topping)}}func(b*BasePizza)Bake(){fmt.Println("Bake for 25 minutes at 350")}func(b*BasePizza)Cut(){fmt.Println("Cutting the pizza into diagonal slices")}func(b*BasePizza)Box(){fmt.Println("Place pizza in official PizzaStore box")}func(b*BasePizza)GetName()string{returnb.name}// NYStyleCheesePizza structtypeNYStyleCheesePizzastruct{BasePizza}funcNewNYStyleCheesePizza()*NYStyleCheesePizza{pizza:=&NYStyleCheesePizza{}pizza.name="NY Style Sauce and Cheese Pizza"pizza.dough="Thin Crust Dough"pizza.sauce="Marinara Sauce"pizza.toppings=[]string{"Grated Reggiano Cheese"}returnpizza}// ChicagoStyleCheesePizza structtypeChicagoStyleCheesePizzastruct{BasePizza}funcNewChicagoStyleCheesePizza()*ChicagoStyleCheesePizza{pizza:=&ChicagoStyleCheesePizza{}pizza.name="Chicago Style Deep Dish Cheese Pizza"pizza.dough="Extra Thick Crust Dough"pizza.sauce="Plum Tomato Sauce"pizza.toppings=[]string{"Shredded Mozzarella Cheese"}returnpizza}func(c*ChicagoStyleCheesePizza)Cut(){fmt.Println("Cutting the pizza into square slices")}// PizzaStore interfacetypePizzaStoreinterface{CreatePizza(pizzaTypestring)PizzaOrderPizza(pizzaTypestring)Pizza}// BasePizzaStore structtypeBasePizzaStorestruct{createPizzafunc(pizzaTypestring)Pizza}func(b*BasePizzaStore)CreatePizza(pizzaTypestring)Pizza{returnb.createPizza(pizzaType)}func(b*BasePizzaStore)OrderPizza(pizzaTypestring)Pizza{pizza:=b.CreatePizza(pizzaType)ifpizza==nil{fmt.Printf("Sorry, we don't have %s pizza.\n",pizzaType)returnnil}fmt.Printf("--- Making a %s ---\n",pizza.GetName())pizza.Prepare()pizza.Bake()pizza.Cut()pizza.Box()returnpizza}// NYPizzaStore structtypeNYPizzaStorestruct{BasePizzaStore}funcNewNYPizzaStore()*NYPizzaStore{store:=&NYPizzaStore{}store.createPizza=func(pizzaTypestring)Pizza{ifpizzaType=="cheese"{returnNewNYStyleCheesePizza()}// Add other pizza types herereturnnil}returnstore}// ChicagoPizzaStore structtypeChicagoPizzaStorestruct{BasePizzaStore}funcNewChicagoPizzaStore()*ChicagoPizzaStore{store:=&ChicagoPizzaStore{}store.createPizza=func(pizzaTypestring)Pizza{ifpizzaType=="cheese"{returnNewChicagoStyleCheesePizza()}// Add other pizza types herereturnnil}returnstore}funcmain(){nyStore:=NewNYPizzaStore()chicagoStore:=NewChicagoPizzaStore()pizza:=nyStore.OrderPizza("cheese")ifpizza!=nil{fmt.Printf("Ethan ordered a %s\n\n",pizza.GetName())}pizza=chicagoStore.OrderPizza("cheese")ifpizza!=nil{fmt.Printf("Joel ordered a %s\n\n",pizza.GetName())}// Test with a non-existent pizza typepizza=nyStore.OrderPizza("pepperoni")ifpizza!=nil{fmt.Printf("Ethan ordered a %s\n\n",pizza.GetName())}}/* OUTPUT:--- Making a NY Style Sauce and Cheese Pizza ---Preparing NY Style Sauce and Cheese PizzaTossing Thin Crust DoughAdding Marinara SauceAdding toppings: Grated Reggiano CheeseBake for 25 minutes at 350Cutting the pizza into diagonal slicesPlace pizza in official PizzaStore boxEthan ordered a NY Style Sauce and Cheese Pizza--- Making a Chicago Style Deep Dish Cheese Pizza ---Preparing Chicago Style Deep Dish Cheese PizzaTossing Extra Thick Crust DoughAdding Plum Tomato SauceAdding toppings: Shredded Mozzarella CheeseBake for 25 minutes at 350Cutting the pizza into square slicesPlace pizza in official PizzaStore boxJoel ordered a Chicago Style Deep Dish Cheese PizzaSorry, we don't have pepperoni pizza.*/