Design patterns and OOP design principles
Design patterns and OOP principles
The exam asks you to recognise a pattern from a structural description and implement its Pythonic form while respecting SOLID and composition-over-inheritance.
Creational. Singleton guarantees one instance; Pythonic forms are a module-level instance, a __new__ override, or a metaclass. Factory Method defers instantiation to subclasses; Abstract Factory groups related factories behind one interface.
Structural. Facade gives a simplified entry point over several subsystems. Proxy keeps the subject's interface but intercepts access - lazy loading, caching, access control, remote calls.
Behavioural. Observer: a subject holds a list of subscribers and notifies them on change. Command: a request becomes an object with execute() (often undo()), enabling queues and undo stacks. Template Method: a base class defines the algorithm skeleton and subclasses fill in abstract hooks - inheritance-based. State: an object alters behaviour when its internal state changes, typically by delegating to a state object.
Worked example
class Report(ABC):
def build(self):
self.gather(); self.format(); self.save()
@abstractmethod
def gather(self): ...
Subclasses override only the hooks, never build, so call order is fixed in one place. Contrast Strategy, which swaps an algorithm object at runtime via composition: the exam often offers both answers, and the discriminator is a fixed call sequence in a superclass versus a swappable collaborator.
Traps
- Singleton via
__new__still runs__init__on every construction - guard it. @abstractmethodonly bites when the class actually inheritsABC(or setsABCMeta).- Proxy and Decorator both wrap; Proxy controls access to one subject, Decorator stacks behaviour.
- Observer lists holding strong references leak observers unless you unsubscribe.