Overview

A design pattern is a named, general solution to a common problem encountered in software design. It does not provide finished code but rather a template that developers can adapt to their specific needs. Patterns capture best practices and trade-offs so teams can communicate architecture and intent with a shared vocabulary. In software engineering, design patterns are particularly associated with object-oriented systems but the concept applies to other paradigms as well.

Core characteristics

Design patterns tend to be:

  • Abstract: They describe structure and collaboration, not implementation details.
  • Reusable: Applicable across projects and languages with suitable adaptation.
  • Documented: Typically captured with a name, intent, motivation, structure and consequences.

Common categories and examples

Patterns are often grouped by intent. Typical categories include:

  • Creational: Control object creation (e.g., Singleton, Factory Method, Abstract Factory).
  • Structural: Compose classes and objects into larger structures (e.g., Adapter, Decorator, Composite).
  • Behavioral: Manage algorithms and object interactions (e.g., Strategy, Observer, Command).

History and development

The modern movement to catalog and name software design patterns gained momentum in the mid-1990s, when practitioners distilled recurring designs from large codebases and published collections of canonical patterns. Naming patterns reduced duplicate design effort and improved discussion across teams and literature.

Uses, benefits and examples

Design patterns help teams reason about architecture, speed development, and avoid subtle errors by reusing proven approaches. For example, the Observer pattern supports event-driven systems by decoupling subjects from listeners, while the Adapter lets legacy code interoperate with new interfaces without invasive changes. Patterns are taught in software engineering courses and appear in code reviews, libraries and frameworks.

Criticism and guidance

While patterns codify useful practices, they can be misused. Overuse or premature introduction of patterns adds unnecessary complexity. Good guidance is to prefer simple code first, apply patterns when a clear problem or recurrence appears, and document intent so future maintainers understand the chosen trade-offs.