codingstairs
NotesEDULifeContact
⌕Search⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

Get in touch

Send without signing in. Add your email if you'd like a reply.

  • Leave a message anonymously →
  • ✉ warragon112@gmail.com
  • KakaoTalk Open Chat ↗

© 2026 codingstairs

  • Notes
  • EDU
  • Search
  • Life
  • Contact
  • Legal
  • RSS
  • GitHub
Notes›programming

Design Patterns — Names for Recurring Solutions

Published 2026-04-28· Updated 2026-05-18·0 views

Design Patterns — Names for Recurring Solutions

Solving similar problems repeatedly produces similar shapes. As object orientation went mainstream in the 1990s, a book came out that named and organized those repeated shapes, and patterns became the shared language of dev culture. This article covers the origins of patterns, the classification of the 23 GoF patterns, the meaning of the seven you meet most often, functional equivalents, anti-patterns, and the view that patterns are tools, not goals.

1. About design patterns

The flagship text is Design Patterns: Elements of Reusable Object-Oriented Software, published in 1994. The four authors — Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides — earned the nickname "Gang of Four (GoF)". The book classified 23 patterns and rooted the term "design pattern" in computer science.

The inspiration that predates GoF is architect Christopher Alexander's A Pattern Language (1977). It named recurring good shapes in architecture, and GoF carried the same idea to software.

Later came Martin Fowler's Patterns of Enterprise Application Architecture (2002), tactical patterns from domain-driven design, concurrency patterns, functional patterns — the catalog has expanded to today.

2. Classification of the 23 GoF patterns

Category Patterns
Creational Singleton · Factory Method · Abstract Factory · Builder · Prototype
Structural Adapter · Bridge · Composite · Decorator · Facade · Flyweight · Proxy
Behavioral Chain of Responsibility · Command · Iterator · Mediator · Memento · Observer · State · Strategy · Template Method · Visitor · Interpreter

Memorizing all 23 is rare. Being comfortable with the seven most common ones gets you far enough.

3. Singleton — only one instance

A globally unique object. Configuration objects, loggers, DB pools commonly use this:

// Common shape
const config = { apiUrl: "...", timeout: 5000 };
export default config;

// Class form
class Logger {
  static instance;
  static getInstance() {
    if (!Logger.instance) Logger.instance = new Logger();
    return Logger.instance;
  }
}

Overuse leads to test difficulties (global state) and multithreaded synchronization issues. The critique "an object-oriented dress on a global variable" comes up often.

4. Factory — delegate creation to a function

Don't call new directly; delegate the choice of which kind to create to a factory function:

function createUser(role) {
  if (role === "admin") return new AdminUser();
  if (role === "guest") return new GuestUser();
  return new RegularUser();
}

The caller doesn't need to know which class is built.

5. Observer — broadcast change

When one object changes, subscribers get notified:

class EventBus {
  listeners = new Map();
  on(event, fn) {
    if (!this.listeners.has(event)) this.listeners.set(event, []);
    this.listeners.get(event).push(fn);
  }
  emit(event, data) {
    this.listeners.get(event)?.forEach(fn => fn(data));
  }
}

The browser's addEventListener, Node's EventEmitter, and RxJS's Observable are all this pattern.

6. Strategy · Adapter · Decorator · Iterator

Strategy — pick one of several implementations of the same interface at runtime:

const sortStrategies = {
  asc: (a, b) => a - b,
  desc: (a, b) => b - a,
  byName: (a, b) => a.name.localeCompare(b.name),
};
arr.sort(sortStrategies[mode]);

Adapter — when the shape of existing code doesn't match new code, wedge a shape-matcher between them:

function fetchAllPromise() {
  return new Promise((resolve, reject) => {
    legacyLib.fetchAll((err, data) => err ? reject(err) : resolve(data));
  });
}

Decorator — add behavior without changing the object itself:

function withLogging(fn) {
  return (...args) => {
    console.log("call", fn.name, args);
    const r = fn(...args);
    console.log("ret", r);
    return r;
  };
}

const loggedAdd = withLogging((a, b) => a + b);

Python's @decorator, TS's @experimental_decorator, and Java / Spring annotations are the same idea.

Iterator — hide the internal representation and expose only a traversal interface:

const it = arr[Symbol.iterator]();
it.next(); // { value: 0, done: false }

for (const x of arr) { /* ... */ }

for...of, Python's for x in xs, Java's Iterable are all this pattern.

7. Functional equivalents

Some OOP patterns express naturally as functions and closures in functional languages. It's not that "the pattern disappeared" — the language absorbed it as a first-class feature:

OOP pattern Functional equivalent
Strategy first-class function as argument
Command closure
Observer reactive stream · pub-sub
Iterator lazy sequence · generator
Decorator higher-order function
Template Method function composition
Singleton module (evaluated once)

Peter Norvig's 1996 talk Design Patterns in Dynamic Languages is often cited for noting that 16 of the 23 patterns simplify in dynamic languages.

8. Pattern families beyond GoF

  • Enterprise patterns (Fowler 2002) — Repository · Unit of Work · DAO · MVC · MVP · MVVM.
  • Concurrency patterns — Producer-Consumer · Read-Write Lock · Actor · Future / Promise.
  • Distributed system patterns — Circuit Breaker · Bulkhead · Retry · Saga · Event Sourcing · CQRS.
  • DDD tactical patterns — Entity · Value Object · Aggregate · Domain Service.
  • Functional patterns — Functor · Monad · Applicative · Lens.

9. Patterns aren't memorized — they emerge as names

It's natural for the name to come to mind when, while writing code, a similar shape repeats and needs a label:

1) Write the code (without thinking about patterns)
2) The same shape shows up a second time → ask if there's a familiar name for it
3) If there is, apply the pattern. Communication with teammates speeds up
4) If there isn't, don't manufacture one. Simple code wins

Anti-flow — "let's apply 5 design patterns to this project" → the code usually gets more complex.

10. Common stumbles

Pattern fetish — wedging a Factory or Strategy where a simple function would do, doubling the code. Patterns are a burden for small code.

God Object — one class doing too much. An anti-pattern.

Anemic Domain Model — domain objects become data buckets while all behavior lives in services. Anti-pattern from a DDD perspective.

Spaghetti Code — flow tangled, untraceable. Pattern absent.

Singleton overuse — global state makes testing hard. Check whether dependency injection (DI) can replace it.

Same name, different intent — even "Adapter" can mean something different in your code than in GoF's definition. Same word doesn't mean same thing.

The myth that patterns answer everything — patterns are vocabulary. The view that good design uses few patterns is also common.

Closing thoughts

Design patterns aren't tools to memorize but vocabulary for communication. When the same shape appears a second time, naming it speeds up the discussion. In dynamic languages (JS, Python), more than half of the 23 patterns are absorbed by first-class functions and modules and become simpler. The myth that good design uses many patterns may run in reverse — KISS comes first.

Next

  • oop-vs-functional
  • (programming end)

We refer to Design Patterns: Elements of Reusable Object-Oriented Software (1994) · A Pattern Language (Christopher Alexander 1977) · Patterns of Enterprise Application Architecture (Martin Fowler 2002) · Design Patterns in Dynamic Languages (Peter Norvig 1996) · Refactoring (Martin Fowler) · Refactoring.Guru · Game Programming Patterns (Robert Nystrom) · Domain-Driven Design (Eric Evans 2003) · Anti-Patterns (Wikipedia).

More in programming

All in this category →
  • OOP and Functional — Two Views Coexisting
  • Big O — Notation for Algorithm Performance
  • Data Structures — Containers for Data