Design Patterns in Practice: Strategy, Observer, Factory, and Their Modern Software Engineering Applications
Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides, 1994) established 23 patterns as a shared software engineering vocabulary, enabling concise communication of complex design intent. But overuse is equally common — unnecessary abstraction layers add complexity rather than reducing it. The key to design patterns is identifying the problem, not applying patterns for their own sake.
Strategy Pattern
Problem: you have an operation (sorting, payment, discount calculation) that needs to support multiple implementations, possibly switched at runtime.
Solution: encapsulate each implementation as a separate class implementing a common interface (strategy class); the caller uses the interface, with the concrete strategy injected at runtime.
Real examples: e-commerce discount systems (new user/member/holiday discount strategies), payment processing (credit card/PayPal/crypto strategies), compression tools (ZIP/GZIP/LZ4 strategies). Modern dependency injection frameworks (Spring, FastAPI DI) implement the strategy pattern concept at the architecture level.
Observer Pattern
Problem: one object’s (Subject’s) state changes need to notify multiple dependent objects (Observers), but the Subject shouldn’t be tightly coupled to its Observers.
Solution: the Subject maintains an observer list and notifies all registered observers on state change. This is the foundational model for event-driven architecture and reactive programming — JavaScript’s `addEventListener`, Node.js’s `EventEmitter`, and RxJS Observables are all Observer pattern variants.
In distributed systems, message queues (Kafka, RabbitMQ) and Pub/Sub systems (Redis Pub/Sub, Google Pub/Sub) are Observer pattern implementations at distributed scale.
Pattern Evolution in Modern Engineering
Functional programming’s growth has made some traditional OO patterns unnecessary or changed in form — the Strategy pattern in higher-order-function languages simply passes a function, requiring no interface or class. Understanding the intent matters more than memorizing canonical implementations. Refactoring.Guru provides multi-language modern implementation examples.




