Chapter 03 · Article 08 of 55

Introduction to Design Patterns

Design patterns are reusable solutions to commonly occurring problems in software design. They are not finished code you can plug directly into your application - they are templ…

Article outline13 sections on this page

Overview

Design patterns are reusable solutions to commonly occurring problems in software design. They are not finished code you can plug directly into your application - they are templates, blueprints, and proven approaches that guide you toward solving recurring architectural challenges.

Why do design patterns exist?

Software engineers kept solving the same structural problems repeatedly - managing object creation, composing classes into larger structures, and defining communication between objects. Patterns emerged as a shared vocabulary that allows teams to communicate complex ideas succinctly. Instead of explaining an entire object-creation strategy, you say "use a Factory" and every experienced developer understands the intent.

The concept of patterns originated in architecture. Christopher Alexander introduced the idea in A Pattern Language (1977), describing recurring solutions to problems in building design. Software engineers adopted this philosophy in the early 1990s, culminating in the landmark 1994 book Design Patterns: Elements of Reusable Object-Oriented Software by the Gang of Four (GoF).


The Gang of Four (GoF)

The term "Gang of Four" refers to four authors who formalized 23 design patterns:

AuthorContribution
Erich GammaLed pattern cataloguing; later created JUnit and contributed to Eclipse IDE
Richard HelmFocused on structural patterns and pattern documentation format
Ralph JohnsonBrought academic rigour; research in frameworks and reflection
John VlissidesContributed to pattern relationships and consequences analysis

Their 1994 book catalogued patterns observed in production systems (primarily C++ and Smalltalk). It did not invent these patterns - it named, documented, and systematised them. The book remains the definitive reference, though modern languages have rendered some patterns unnecessary (e.g., Iterator is built into most standard libraries).

Key insight: GoF patterns target object-oriented design. They assume inheritance, polymorphism, and encapsulation as foundational mechanisms.


Pattern Categories

The 23 GoF patterns divide into three families:

CategoryPurposeExamplesWhen to Use
CreationalControl object creation mechanismsSingleton, Factory Method, Abstract Factory, Builder, PrototypeWhen direct instantiation creates coupling, complexity, or inflexibility
StructuralCompose classes/objects into larger structuresAdapter, Bridge, Composite, Decorator, Facade, Flyweight, ProxyWhen you need to simplify interfaces, add behaviour, or unify incompatible systems
BehaviouralDefine communication and responsibility between objectsObserver, Strategy, Command, Chain of Responsibility, State, Template Method, Visitor, Mediator, Memento, IteratorWhen algorithms vary, objects need loose coupling, or responsibilities must be distributed

Rule of thumb: Creational patterns abstract what gets created. Structural patterns abstract how things are composed. Behavioural patterns abstract how things communicate.


Anatomy of a Pattern

Every GoF pattern is documented using a consistent structure:

SectionDescription
IntentA one-sentence summary of what the pattern does
MotivationA scenario illustrating the problem and how the pattern solves it
ApplicabilityConditions under which the pattern is appropriate
StructureUML class/sequence diagrams showing participants
ParticipantsClasses/objects involved and their roles
CollaborationsHow participants interact at runtime
ConsequencesTrade-offs - what you gain and what you pay

When studying or presenting a pattern, always address Intent first (what problem does it solve?) and Consequences last (what are the trade-offs?). Interviewers value trade-off awareness over rote definitions.


When to Use Design Patterns

SituationRecommended Pattern(s)
Need exactly one instance globallySingleton
Object creation logic is complex with many parametersBuilder
Must switch between algorithm families at runtimeStrategy
Want to decouple event producers from consumersObserver
Need to support undo/redo operationsCommand + Memento
Wrapping a legacy system with a clean interfaceAdapter or Facade
Adding responsibilities dynamically without subclassingDecorator
Creating families of related objects without specifying concrete classesAbstract Factory
Need to traverse a collection without exposing internalsIterator
Object creation should be deferred to subclassesFactory Method
Cloning expensive-to-create objectsPrototype

Decision framework: If you find yourself writing conditional logic to decide which class to instantiate or which algorithm to run, a pattern likely applies.


When NOT to Use Design Patterns

Design patterns are tools, not goals. Misapplication causes more harm than the problems they solve.

1. Over-engineering (YAGNI violation) Applying Abstract Factory when you have one concrete implementation and no foreseeable variation. You add indirection without benefit.

2. Pattern Fever Forcing every class into a pattern. Not every object needs a Factory. Not every callback needs an Observer. If the straightforward approach is readable and maintainable, prefer it.

3. KISS Violation A Singleton with double-checked locking in a language that provides module-level constants is unnecessary complexity. Modern languages often provide idiomatic alternatives that eliminate the need for classical patterns.

4. Wrong Abstraction Level Using Visitor in a codebase with 2 node types that will never grow. The pattern's complexity outweighs its benefit when the problem space is small and stable.

5. Cargo Culting Copying a pattern from a tutorial without understanding the problem it solves in your context. Patterns are context-dependent - the same pattern can be brilliant or disastrous depending on constraints.

Guideline: Apply a pattern when you feel the pain of not having it - not preemptively.


Pattern Relationships

Patterns do not exist in isolation. They complement, compete with, and build upon each other:

                    ┌─────────────────────────────────────────┐
                    │           CREATIONAL                      │
                    │                                           │
                    │  Abstract Factory ──uses──► Factory Method│
                    │        │                        │         │
                    │        │ creates               │ creates  │
                    │        ▼                        ▼         │
                    │    Prototype            Singleton         │
                    │        │                    │             │
                    │        └───► Builder ◄──────┘             │
                    └──────────────────┬──────────────────────-┘
                                       │
                         objects flow into
                                       ▼
                    ┌─────────────────────────────────────────┐
                    │           STRUCTURAL                      │
                    │                                           │
                    │  Adapter ◄──competes──► Bridge            │
                    │     │                      │              │
                    │     ▼                      ▼              │
                    │  Facade ──simplifies──► Composite         │
                    │     │                      │              │
                    │     └──► Decorator ◄───────┘              │
                    │              │         Proxy              │
                    └──────────────┼──────────────────────────-┘
                                   │
                    communicates via
                                   ▼
                    ┌─────────────────────────────────────────┐
                    │           BEHAVIOURAL                     │
                    │                                           │
                    │  Observer ◄──notifies──► Mediator         │
                    │      │                      │            │
                    │      ▼                      ▼            │
                    │  Command ──────► Chain of Responsibility  │
                    │      │                      │            │
                    │      ▼                      ▼            │
                    │  Strategy ◄──swaps──► State               │
                    │      │                                    │
                    │      └──► Template Method ──► Iterator    │
                    └─────────────────────────────────────────-┘

Key relationships:

  • Abstract Factory often uses Factory Method internally
  • Builder can use Prototype for complex part construction
  • Decorator and Strategy both add behaviour - Decorator wraps, Strategy delegates
  • State and Strategy share identical structure but differ in intent

Creational Patterns Overview

Creational patterns abstract the instantiation process, making systems independent of how objects are created, composed, and represented.

PatternOne-linerWhen to Use
SingletonEnsures a class has exactly one instance with a global access pointShared resources (config, connection pool, logger)
Factory MethodDefines an interface for creating objects, letting subclasses decide which class to instantiateWhen a class cannot anticipate the type of objects it must create
Abstract FactoryCreates families of related objects without specifying concrete classesWhen the system must be independent of how products are created and composed
BuilderSeparates construction of a complex object from its representationWhen construction involves many steps or optional parameters
PrototypeCreates new objects by cloning an existing instanceWhen instantiation is expensive and objects differ only slightly

Creational patterns shift responsibility: Instead of the client knowing exactly which class to instantiate, the pattern encapsulates that decision. This is the foundation of the Dependency Inversion Principle - depend on abstractions, not concretions.


Common Misconceptions

MythReality
"Design patterns are only for Java/C++"Patterns are language-agnostic concepts; implementation varies by language
"Singleton is an anti-pattern"Singleton is problematic when misused (global mutable state); it's valid for genuinely shared resources
"Using patterns makes code better automatically"Misapplied patterns increase complexity; they must solve a real problem
"Patterns are outdated"Core problems persist; some patterns are built into languages, but understanding why remains essential
"You should use as many patterns as possible"Fewer patterns applied correctly beats many patterns applied poorly
"Patterns replace architecture"Patterns are micro-level solutions; architecture addresses system-level concerns
"Factory and Abstract Factory are the same"Factory Method uses inheritance; Abstract Factory uses composition to create families

Interview Follow-ups

Q1: What is the difference between a design pattern and an algorithm?

A: An algorithm is a step-by-step procedure to solve a computational problem (sorting, searching). A design pattern is a structural template for organising code to solve a design problem (flexibility, decoupling, reuse). Algorithms solve "how to compute X"; patterns solve "how to structure code so X is maintainable."

Q2: Can you use multiple design patterns together? Give an example.

A: Absolutely. A common combination: Abstract Factory (creates UI components) + Singleton (ensures one factory instance) + Observer (UI components notify listeners on state change). MVC itself combines Observer (View observes Model), Strategy (Controller is a strategy for the View), and Composite (Views can be nested).

Q3: How do design patterns relate to SOLID principles?

A: Patterns are implementations of SOLID principles. Factory Method applies the Open/Closed Principle (extend via new subclasses without modifying existing code). Strategy applies Dependency Inversion (depend on an abstraction, not a concrete algorithm). Observer applies the Single Responsibility Principle (separates event production from consumption).

Q4: Why might you choose Prototype over Factory Method?

Hint: Think about when object creation is expensive and the new object differs only slightly from an existing one. Consider deep vs shallow copy implications.

Q5: In what scenario would you combine Builder with Singleton?

Hint: Consider configuration objects that are complex to construct but should exist only once. Think about thread-safe lazy initialisation of a multi-step build.


Counter Questions to Ask Interviewer

Use these to demonstrate depth and clarify requirements:

  1. "What's the expected rate of change in this system?" - Determines whether patterns for extensibility (Strategy, Factory) are warranted or over-engineering.

  2. "Are there existing patterns or conventions in the codebase I should follow?" - Shows awareness that consistency matters more than theoretical perfection.

  3. "What are the concurrency requirements?" - Singleton, Observer, and Builder all have thread-safety implications that change implementation significantly.

  4. "Is this a library/framework or an application?" - Libraries benefit heavily from Template Method and Strategy; applications may prefer simpler direct approaches.

  5. "What's the team's familiarity with these patterns?" - A pattern the team doesn't understand creates maintenance burden regardless of technical merit.


References & Whitepapers

ResourceDescription
Design Patterns: Elements of Reusable Object-Oriented Software (Gamma et al., 1994)The definitive GoF reference; 23 patterns with C++/Smalltalk examples
Head First Design Patterns (Freeman & Robson, 2004)Accessible introduction with Java examples and visual learning approach
A Pattern Language (Christopher Alexander, 1977)The architectural origin of pattern thinking; 253 patterns for buildings and towns
Pattern-Oriented Software Architecture (Buschmann et al., 1996)Extends GoF to architectural patterns (Layers, Pipes & Filters, Broker)
Refactoring to Patterns (Kerievsky, 2004)Bridges refactoring and patterns; shows when and how to introduce patterns incrementally


This article serves as the gateway to the creational design patterns series. Each subsequent article dives deep into one pattern with real-world examples, code implementations, trade-off analysis, and interview-ready explanations.