← Back to Software Architecture

18 Software Design Patterns

Eighteen design patterns for object creation, composition, and behavioural flow.

Software ArchitectureDesign PatternsSoftware Development

Design patterns are most useful as shared vocabulary. They do not replace judgment, and they are not mandatory decoration for every codebase. Their value is that they describe recurring ways to organise object interaction when the naive design starts to strain.

  1. Singleton. Use sparingly. It gives one shared instance, but it also hides dependencies and makes tests harder when global state leaks across cases.

  2. Factory Method. Moves object creation behind a named decision point so callers depend on an interface instead of a concrete constructor.

  3. Abstract Factory. Useful when several related objects must vary together, such as platform-specific widgets or environment-specific integrations.

  4. Builder. Separates complex construction from representation, which helps when an object has many optional parts or ordering rules.

  5. Prototype. Clones existing instances instead of building from scratch. Handy when setup is expensive or object shape is discovered dynamically.

  6. Adapter. Translates one interface into another without changing either side's core behaviour. It is common at integration boundaries.

  7. Facade. Presents a simpler front over a complicated subsystem. Good facades reduce coupling by hiding implementation noise from callers.

  8. Decorator. Adds behaviour without subclass explosion. Wrapping is often cleaner than inheritance when features can be combined at runtime.

  9. Proxy. Controls access to another object for caching, laziness, authorisation, or remote invocation.

  10. Composite. Lets clients treat individual objects and groups uniformly, which is why it appears in trees, menus, and document models.

  11. Strategy. Encapsulates interchangeable algorithms behind one contract. It keeps branching logic from spreading across the system.

  12. Command. Turns an action into an object that can be queued, logged, retried, or undone.

  13. Observer. Pushes change notifications to subscribers. Powerful for decoupling, but dangerous when update flow becomes hard to trace.

  14. Template Method. Defines algorithm structure in a base type while letting subclasses fill in specific steps. Useful, though often replaced by composition in modern code.

  15. State. Represents state-specific behaviour as dedicated objects instead of large conditional blocks.

  16. Iterator. Provides sequential access without exposing the collection's internal representation.

  17. Chain of Responsibility. Passes a request through handlers until one deals with it. Common in middleware pipelines and validation stacks.

  18. Mediator. Centralises interaction between components that would otherwise talk to each other directly, reducing graph complexity.

Patterns help most when they make a design easier to explain and easier to change. If using a pattern makes the code more ceremonial than the problem deserves, the pattern is solving the wrong problem.