CS 112 › Lesson 8 of 10

Design Patterns

Lesson 8 · OKSTEM College · Associate of Science in Computer Science

What Are Design Patterns?

Design patterns are reusable solutions to common software design problems. They are not code you copy-paste — they are templates you adapt. Three classic categories: Creational (how objects are made), Structural (how objects are composed), Behavioural (how objects communicate).

Creational: Singleton

A Singleton ensures only one instance of a class ever exists. Useful for configuration, logging, or database connections.

class Config: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.debug = False return cls._instance a = Config(); b = Config() print(a is b) # True — same object a.debug = True print(b.debug) # True — b IS a

Creational: Factory Method

A Factory delegates object creation to a method, decoupling the caller from concrete classes.

class Notifier: def send(self, msg): raise NotImplementedError class EmailNotifier(Notifier): def send(self, msg): print(f"Email: {msg}") class SMSNotifier(Notifier): def send(self, msg): print(f"SMS: {msg}") def notifier_factory(channel: str) -> Notifier: options = {"email": EmailNotifier, "sms": SMSNotifier} if channel not in options: raise ValueError(f"Unknown channel: {channel}") return options[channel]() notifier_factory("sms").send("Hello!") # SMS: Hello!

Behavioural: Observer

The Observer pattern lets objects subscribe to events. When the subject changes, all subscribers are notified automatically.

class EventBus: def __init__(self): self._listeners: dict = {} def subscribe(self, event, fn): self._listeners.setdefault(event, []).append(fn) def publish(self, event, data=None): for fn in self._listeners.get(event, []): fn(data) bus = EventBus() bus.subscribe("login", lambda u: print(f"Welcome, {u}!")) bus.subscribe("login", lambda u: print(f"Logging login for {u}")) bus.publish("login", "Alice") # Welcome, Alice! # Logging login for Alice

Practice Problems

1. When would you choose Singleton over a module-level variable?

When you need lazy initialization (create the object only when first needed), or when you want to encapsulate related state and methods together, or when you need to control subclassing. Module-level variables are simpler but can't be subclassed or lazily initialized as cleanly.

2. Add a "logout" event to the EventBus example that prints a farewell.

bus.subscribe("logout", lambda u: print(f"Goodbye, {u}!")) bus.publish("logout", "Alice") # Goodbye, Alice!

Knowledge Check

A Singleton ensures

That's normal instantiation, not Singleton.
Correct — subsequent calls to the constructor return the same object.
Singleton doesn't inherently prevent subclassing (though subclassing Singletons is tricky).
Singleton objects can have instance methods.
Recap: Singleton overrides __new__ to return the cached instance if one already exists.

The Factory pattern's main benefit is

Performance is not the motivation.
Correct — the caller asks for a 'notifier' without knowing which concrete class it gets.
Factory doesn't affect inheritance.
Those are separate patterns.
Recap: notifier_factory('sms') returns an SMSNotifier — the caller never imports SMSNotifier directly. Swap implementations without changing call sites.

The Observer pattern is best described as

That's tight coupling — the opposite of Observer.
Correct — publish/subscribe decouples producers from consumers.
That's Factory.
That's Singleton.
Recap: Observer = event bus pattern. Subscribers register; when an event fires, all subscribers are called. Neither side knows the other's details.

Design patterns are

They are templates and concepts, not copy-paste code.
Correct — you adapt the pattern to your language and context.
Patterns apply at any scale; Singleton is common even in small scripts.
Patterns are language-agnostic concepts, not library code.
Recap: patterns are a shared vocabulary for design. Saying 'use an Observer here' communicates an architecture quickly to other engineers.

Which pattern category does 'Factory' belong to?

Correct — Creational patterns deal with how objects are instantiated.
Structural patterns deal with how objects are composed (Adapter, Decorator, etc.).
Behavioural patterns deal with how objects communicate (Observer, Strategy, etc.).
Not one of the classic GoF categories.
Recap: Creational = Singleton, Factory, Builder. Structural = Adapter, Decorator, Facade. Behavioural = Observer, Strategy, Command.

← PreviousNext →