How to Understand Creational Design Patterns with Example

Understanding Creational Design Patterns can be easier with examples. Creational Design Patterns focus on object creation mechanisms, providing flexibility and decoupling the object creation process from the client code. Here are three common Creational Design Patterns with examples:

  1. Factory Method Pattern:
    The Factory Method Pattern provides an interface for creating objects, but allows subclasses to decide which class to instantiate. It promotes loose coupling and encapsulation. Here’s an example:

    class Animal:
        def speak(self):
            pass
    
    class Dog(Animal):
        def speak(self):
            return "Woof!"
    
    class Cat(Animal):
        def speak(self):
            return "Meow!"
    
    class AnimalFactory:
        def create_animal(self, animal_type):
            if animal_type == "dog":
                return Dog()
            elif animal_type == "cat":
                return Cat()
    
    # Usage:
    factory = AnimalFactory()
    dog = factory.create_animal("dog")
    cat = factory.create_animal("cat")
    print(dog.speak())  # Output: Woof!
    print(cat.speak())  # Output: Meow!
    

    In this example, the AnimalFactory class encapsulates the object creation logic. It provides a create_animal method that returns the appropriate animal object based on the input.

  2. Singleton Pattern:
    The Singleton Pattern ensures that only one instance of a class is created and provides a global point of access to it. It is useful when you need to restrict object creation to a single instance. Here’s an example:

    class Singleton:
        _instance = None
    
        @staticmethod
        def get_instance():
            if not Singleton._instance:
                Singleton._instance = Singleton()
            return Singleton._instance
    
    # Usage:
    instance1 = Singleton.get_instance()
    instance2 = Singleton.get_instance()
    print(instance1 is instance2)  # Output: True
    

    In this example, the Singleton class ensures that only one instance is created by providing a static method get_instance() that returns the same instance every time it is called.

  3. Builder Pattern:
    The Builder Pattern separates the construction of complex objects from their representation, allowing the same construction process to create different representations. It simplifies object creation by providing a step-by-step approach. Here’s an example:

    class Pizza:
        def __init__(self):
            self.crust = None
            self.sauce = None
            self.toppings = []
    
        def add_crust(self, crust):
            self.crust = crust
    
        def add_sauce(self, sauce):
            self.sauce = sauce
    
        def add_topping(self, topping):
            self.toppings.append(topping)
    
        def __str__(self):
            return f"Pizza with {self.crust} crust, {self.sauce} sauce, and {', '.join(self.toppings)} toppings"
    
    class PizzaBuilder:
        def __init__(self):
            self.pizza = Pizza()
    
        def set_crust(self, crust):
            self.pizza.add_crust(crust)
            return self
    
        def set_sauce(self, sauce):
            self.pizza.add_sauce(sauce)
            return self
    
        def add_topping(self, topping):
            self.pizza.add_topping(topping)
            return self
    
        def build(self):
            return self.pizza
    
    # Usage:
    builder = PizzaBuilder()
    pizza = builder.set_crust("thin").set_sauce("tomato").add_topping("cheese").add_topping("mushrooms").build()
    print(pizza)