Fundamentals 9 min read

Master 10 Essential Python Design Patterns with Ready-to-Run Code

This article introduces ten classic software design patterns—Singleton, Factory, Observer, Strategy, Adapter, Builder, Prototype, Decorator, Template Method, and Facade—explaining their purpose, structure, and providing complete Python code examples that demonstrate how to implement and apply each pattern in real projects.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Master 10 Essential Python Design Patterns with Ready-to-Run Code

Design patterns are reusable solutions to common software design problems. The following sections present ten widely used patterns, describe when and why to use them, and give full Python implementations that can be copied into real projects.

1. Singleton Pattern

The Singleton pattern ensures that a class has only one instance and provides a global access point to it.

class Singleton:
    _instance = None

    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

# Using the singleton
instance1 = Singleton()
instance2 = Singleton()
print(instance1 is instance2)  # True

2. Factory Pattern

The Factory pattern separates object creation from its usage, allowing flexible instantiation of related objects.

class Product:
    def operation(self):
        pass

class ConcreteProduct(Product):
    def operation(self):
        print("ConcreteProduct operation")

class ProductFactory:
    @staticmethod
    def create_product():
        return ConcreteProduct()

# Using the factory
product = ProductFactory.create_product()
product.operation()  # "ConcreteProduct operation"

3. Observer Pattern

The Observer pattern defines a one‑to‑many dependency so that when one object changes state, all its dependents are automatically notified.

class Subject:
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        self._observers.append(observer)

    def detach(self, observer):
        self._observers.remove(observer)

    def notify(self):
        for observer in self._observers:
            observer.update()

class Observer:
    def update(self):
        pass

class ConcreteObserver(Observer):
    def update(self):
        print("ConcreteObserver received update")

subject = Subject()
observer = ConcreteObserver()
subject.attach(observer)
subject.notify()  # "ConcreteObserver received update"

4. Strategy Pattern

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.

class Strategy:
    def execute(self):
        pass

class ConcreteStrategyA(Strategy):
    def execute(self):
        print("ConcreteStrategyA execute")

class ConcreteStrategyB(Strategy):
    def execute(self):
        print("ConcreteStrategyB execute")

class Context:
    def __init__(self, strategy):
        self._strategy = strategy

    def execute_strategy(self):
        self._strategy.execute()

# Using the strategy
strategy_a = ConcreteStrategyA()
context = Context(strategy_a)
context.execute_strategy()  # "ConcreteStrategyA execute"
strategy_b = ConcreteStrategyB()
context = Context(strategy_b)
context.execute_strategy()  # "ConcreteStrategyB execute"

5. Adapter Pattern

The Adapter pattern converts the interface of a class into another interface clients expect, allowing incompatible classes to work together.

class Target:
    def request(self):
        pass

class Adaptee:
    def specific_request(self):
        print("Adaptee specific request")

class Adapter(Target):
    def __init__(self, adaptee):
        self._adaptee = adaptee

    def request(self):
        self._adaptee.specific_request()

# Using the adapter
adaptee = Adaptee()
adapter = Adapter(adaptee)
adapter.request()  # "Adaptee specific request"

6. Builder Pattern

The Builder pattern separates the construction of a complex object from its representation, enabling the same construction process to create different representations.

class Product:
    def __init__(self):
        self.parts = []

    def add_part(self, part):
        self.parts.append(part)

    def display(self):
        print("Product parts:", self.parts)

class Builder:
    def build_part_a(self):
        pass
    def build_part_b(self):
        pass
    def get_result(self):
        pass

class ConcreteBuilder(Builder):
    def __init__(self):
        self.product = Product()

    def build_part_a(self):
        self.product.add_part("Part A")

    def build_part_b(self):
        self.product.add_part("Part B")

    def get_result(self):
        return self.product

class Director:
    def construct(self, builder):
        builder.build_part_a()
        builder.build_part_b()

# Using the builder
builder = ConcreteBuilder()
Director().construct(builder)
product = builder.get_result()
product.display()  # "Product parts: ['Part A', 'Part B']"

7. Prototype Pattern

The Prototype pattern creates new objects by copying an existing object, avoiding the cost of creating objects from scratch.

import copy

class Prototype:
    def clone(self):
        pass

class ConcretePrototype(Prototype):
    def __init__(self, value):
        self.value = value

    def clone(self):
        return copy.deepcopy(self)

# Using the prototype
prototype = ConcretePrototype(10)
clone = prototype.clone()
print(clone.value)  # 10

8. Decorator Pattern

The Decorator pattern dynamically adds responsibilities to objects without modifying their structure.

class Component:
    def operation(self):
        pass

class ConcreteComponent(Component):
    def operation(self):
        print("ConcreteComponent operation")

class Decorator(Component):
    def __init__(self, component):
        self._component = component

    def operation(self):
        self._component.operation()

class ConcreteDecorator(Decorator):
    def operation(self):
        super().operation()
        self.added_behavior()

    def added_behavior(self):
        print("ConcreteDecorator added behavior")

# Using the decorator
component = ConcreteComponent()
decorator = ConcreteDecorator(component)
decorator.operation()
# Output:
# "ConcreteComponent operation"
# "ConcreteDecorator added behavior"

9. Template Method Pattern

The Template Method pattern defines the skeleton of an algorithm in a base class, allowing subclasses to override specific steps.

class AbstractClass:
    def template_method(self):
        self.step1()
        self.step2()
        self.step3()

    def step1(self):
        pass
    def step2(self):
        pass
    def step3(self):
        pass

class ConcreteClass(AbstractClass):
    def step2(self):
        print("ConcreteClass step2")

# Using the template method
obj = ConcreteClass()
obj.template_method()
# Output:
# "AbstractClass step1"
# "ConcreteClass step2"
# "AbstractClass step3"

10. Facade Pattern

The Facade pattern provides a simplified interface to a complex subsystem, hiding its internal details.

class SubsystemA:
    def operation_a(self):
        print("SubsystemA operation")

class SubsystemB:
    def operation_b(self):
        print("SubsystemB operation")

class Facade:
    def __init__(self):
        self._subsystem_a = SubsystemA()
        self._subsystem_b = SubsystemB()

    def operation(self):
        self._subsystem_a.operation_a()
        self._subsystem_b.operation_b()

# Using the facade
facade = Facade()
facade.operation()
# Output:
# "SubsystemA operation"
# "SubsystemB operation"

These examples demonstrate how each pattern can be implemented in Python, offering a structured, maintainable, and extensible way to solve recurring design challenges.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsSoftware ArchitectureCreationalStructural
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.