B3.2.5

Explain commonly used design patterns in OOP

A design pattern is a reusable solution template for recurring design problems.

3 min read569 words

What Is a Design Pattern?

A design pattern is a reusable solution template for recurring design problems.

  • It is not finished code.
  • It is language-agnostic guidance for building robust, maintainable systems.
  • It speeds development by reusing proven structures.

Typical Pattern Documentation

Most pattern descriptions include:

  • Intent: what problem the pattern solves
  • Motivation: why this problem matters in real systems
  • Structure: class relationships (often UML)
  • Code example: how it can be implemented

Three Pattern Families

FamilyFocus
CreationalHow objects are created
StructuralHow classes/objects are composed
BehavioralHow objects communicate and cooperate

For this section, focus on: Singleton, Factory, and Observer.

1) Singleton Pattern

Core idea

Ensure a class has exactly one instance and provide global access to it.

Good use cases

  • Shared config manager
  • Logging service
  • A single connection/controller object

Structure (concept)

  • Private/controlled constructor
  • One static/class-level instance reference
  • One access method (e.g., get_instance())

Python example

class SingletonConfig:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.mode = "prod"
        return cls._instance


a = SingletonConfig()
b = SingletonConfig()
print(a is b)  # True

Pros / Cons

ProsCons
Strict control of a shared resourceHarder to test (global state)
Guarantees single instanceCan introduce hidden coupling
Centralized access pointLifetime/reset handling can be awkward

2) Factory Pattern

Core idea

Create objects through a factory method/class instead of direct constructor calls. Client code depends on a common interface, not concrete classes.

Good use cases

  • You do not know exact concrete type at compile/design time
  • New product types are added over time
  • You want to centralize creation logic

Structure (concept)

  • Common product interface/base class
  • Concrete product subclasses
  • Factory that returns interface type but chooses concrete class internally

Python example

class Student:
    def level(self) -> str:
        raise NotImplementedError


class PrimaryStudent(Student):
    def level(self) -> str:
        return "Primary"


class MiddleStudent(Student):
    def level(self) -> str:
        return "Middle"


class StudentFactory:
    @staticmethod
    def create(stage: str) -> Student:
        if stage == "primary":
            return PrimaryStudent()
        if stage == "middle":
            return MiddleStudent()
        raise ValueError("Unknown stage")

Pros / Cons

ProsCons
Centralized creation logicMore classes/abstractions
Easy to add new productsCan become overengineered for small systems
Reduces direct coupling to concrete classesFactory logic may grow complex

3) Observer Pattern

Core idea

Define a one-to-many subscription mechanism:

  • Publisher/Subject stores subscribers
  • When state changes, publisher notifies all subscribers

Good use cases

  • Notifications
  • Event systems
  • UI updates from data changes

Structure (concept)

  • Subscriber interface (e.g., update(...))
  • Publisher with add_subscriber, remove_subscriber, notify
  • Iteration over subscriber list during notification

Python example

class Subscriber:
    def update(self, message: str):
        raise NotImplementedError


class EmailSubscriber(Subscriber):
    def __init__(self, name: str):
        self.name = name

    def update(self, message: str):
        print(f"{self.name} received: {message}")


class Publisher:
    def __init__(self):
        self.subscribers: list[Subscriber] = []

    def add_subscriber(self, s: Subscriber):
        self.subscribers.append(s)

    def remove_subscriber(self, s: Subscriber):
        self.subscribers.remove(s)

    def notify(self, message: str):
        for s in self.subscribers:
            s.update(message)

Pros / Cons

ProsCons
Easy to add new subscribers without changing publisher coreNotification order may be undefined
Decouples sender from receiversPriority/filtered delivery needs extra design
Supports scalable event-driven designDebugging event chains can be harder

Start typing to search all published objectives.