# Choosing a Pattern

> A decision guide that maps concrete code symptoms to the pattern that fixes them, and tells you when plain code beats any pattern.

- kind: guide
- category: design-patterns
- aliases: Pattern selection, Pattern catalog
- canonical: https://aipatterns.dev/guides/choosing-a-pattern
- inspired-by: https://refactoring.guru/design-patterns/catalog

## Start from the symptom, not the pattern

**Pick a pattern only after you can name the concrete problem in the current code that it removes.** "This would be more flexible" is not a problem. "Adding a fourth export format means editing the same `switch` in five files" is.

Work in this order:

1. Name the pain in one sentence, with a file and function.
2. Check the "Prefer no pattern when" list below. Most pains have a smaller fix.
3. Find the symptom in the table. Read the candidate pattern's `## Do not use it when` section before anything else.
4. If two patterns fit, compare their `## Relations` sections. They state the difference directly.

## Symptom to pattern

| Symptom in the code | Candidate | Check first |
|---|---|---|
| `new ConcreteThing()` scattered in code that should not know which concrete type it gets | [Factory Method](https://aipatterns.dev/design-patterns/factory-method.md) | A plain factory function is often enough |
| Several related objects must be created as a matched set (all AWS or all GCP clients) | [Abstract Factory](https://aipatterns.dev/design-patterns/abstract-factory.md) | Only worth it with two or more real families |
| Constructor with many optional parameters, or objects built in several steps | [Builder](https://aipatterns.dev/design-patterns/builder.md) | Named or object parameters may do it |
| Creating an object is expensive and you need many near-identical copies | [Prototype](https://aipatterns.dev/design-patterns/prototype.md) | `structuredClone` or a copy constructor |
| Exactly one instance must exist and be reachable process-wide | [Singleton](https://aipatterns.dev/design-patterns/singleton.md) | Usually pass the instance in instead |
| A third-party or legacy class has the wrong interface for your code | [Adapter](https://aipatterns.dev/design-patterns/adapter.md) | A wrapper function for one call |
| Two independent dimensions of variation multiply into many subclasses | [Bridge](https://aipatterns.dev/design-patterns/bridge.md) | Only if both dimensions really vary |
| Tree of items where leaves and groups must be treated the same | [Composite](https://aipatterns.dev/design-patterns/composite.md) | A recursive function over plain data |
| You need to add behavior (logging, caching, retries) around an object without changing it | [Decorator](https://aipatterns.dev/design-patterns/decorator.md) | Higher-order function or middleware |
| Callers wire together many subsystem objects to do one common task | [Facade](https://aipatterns.dev/design-patterns/facade.md) | A single module-level function |
| Memory blows up from millions of objects that share most of their data | [Flyweight](https://aipatterns.dev/design-patterns/flyweight.md) | Measure first |
| Access to an object needs lazy loading, access control or remote calls | [Proxy](https://aipatterns.dev/design-patterns/proxy.md) | Language-level `Proxy` or a lazy getter |
| A request passes through a sequence of handlers, any of which may handle or reject it | [Chain of Responsibility](https://aipatterns.dev/design-patterns/chain-of-responsibility.md) | An array of functions in a loop |
| Actions must be queued, logged, retried or undone | [Command](https://aipatterns.dev/design-patterns/command.md) | A closure plus a record of inputs |
| Callers depend on a collection's internal layout to traverse it | [Iterator](https://aipatterns.dev/design-patterns/iterator.md) | Built-in iterators and generators |
| Many components call each other directly, forming a tangle | [Mediator](https://aipatterns.dev/design-patterns/mediator.md) | An event bus you already have |
| You need snapshots for undo without exposing internal fields | [Memento](https://aipatterns.dev/design-patterns/memento.md) | Immutable state makes this free |
| Other objects must react when something changes | [Observer](https://aipatterns.dev/design-patterns/observer.md) | Built-in events, signals or streams |
| Behavior depends on an object's mode, with `switch (this.status)` in many methods | [State](https://aipatterns.dev/design-patterns/state.md) | A transition table if behavior is small |
| A `switch` picks between algorithms that compute the same result in different ways | [Strategy](https://aipatterns.dev/design-patterns/strategy.md) | Pass a function |
| Subclasses copy the same workflow and differ in a few steps | [Template Method](https://aipatterns.dev/design-patterns/template-method.md) | Higher-order function with hooks |
| You keep adding operations over a stable set of node types (AST, document tree) | [Visitor](https://aipatterns.dev/design-patterns/visitor.md) | Pattern matching over a union type |

## Prefer no pattern when

- **There are only one or two variants.** An `if` is honest. Wait for the third case. See [Speculative Generality](https://aipatterns.dev/refactoring/smells/speculative-generality.md).
- **The language already has the feature.** First-class functions replace most single-method Strategy, Command and Template Method uses. Generators replace Iterator. Discriminated unions with exhaustive `switch` replace many Visitor uses. Module scope replaces Singleton.
- **A refactoring technique removes the smell.** [Extract Method](https://aipatterns.dev/refactoring/techniques/extract-method.md), [Introduce Parameter Object](https://aipatterns.dev/refactoring/techniques/introduce-parameter-object.md) and [Decompose Conditional](https://aipatterns.dev/refactoring/techniques/decompose-conditional.md) fix more code than any pattern.
- **The code is not going to change.** Patterns pay off on the next change. Stable code gets no return.
- **The team or codebase does not use the pattern elsewhere.** One lone Abstract Factory in a codebase of plain functions is a reading tax for every future contributor.
- **You cannot write a test that the pattern makes easier.** If the test is the same before and after, the pattern bought nothing measurable.
- **The framework already owns that concern.** Dependency injection containers, ORMs and UI frameworks implement Factory, Proxy and Observer for you. Use theirs.

## Selection flowchart

The first chart decides whether you need a pattern at all and which family to look in. Families are explained in [Classification of patterns](https://aipatterns.dev/guides/classification-of-patterns.md).

```mermaid
flowchart TD
  A{"Can you name a concrete pain in current code?"}
  A -->|No| N["Use no pattern"]
  A -->|Yes| B{"Would a function, map or refactoring fix it?"}
  B -->|Yes| N
  B -->|No| C{"Is the pain about creating objects?"}
  C -->|Yes| CR["Creational patterns"]
  C -->|No| D{"Is it about fitting or wrapping objects?"}
  D -->|Yes| ST["Structural patterns"]
  D -->|No| BH["Behavioral patterns"]
```

Behavioral is the largest family and the most common destination. The second chart covers its frequent cases.

```mermaid
flowchart TD
  A{"Does a switch pick an algorithm per call?"}
  A -->|Yes| S["Strategy, or pass a function"]
  A -->|No| B{"Does behavior depend on a mode that changes over time?"}
  B -->|Yes| ST["State"]
  B -->|No| C{"Must others react when something changes?"}
  C -->|Yes| O["Observer"]
  C -->|No| T["Use the symptom table"]
```

## Telling look-alikes apart

Several patterns share a class diagram. Decide by intent:

- [Strategy](https://aipatterns.dev/design-patterns/strategy.md) vs [State](https://aipatterns.dev/design-patterns/state.md): strategies are chosen from outside and ignore each other; states switch themselves.
- [Decorator](https://aipatterns.dev/design-patterns/decorator.md) vs [Proxy](https://aipatterns.dev/design-patterns/proxy.md): a decorator adds behavior and stacks; a proxy controls access and usually manages the real object's lifecycle.
- [Adapter](https://aipatterns.dev/design-patterns/adapter.md) vs [Facade](https://aipatterns.dev/design-patterns/facade.md): an adapter makes one existing interface fit another; a facade invents a simpler interface over many objects.
- [Factory Method](https://aipatterns.dev/design-patterns/factory-method.md) vs [Abstract Factory](https://aipatterns.dev/design-patterns/abstract-factory.md): one product vs a family of products. See [Factory comparison](https://aipatterns.dev/guides/factory-comparison.md).
- [Command](https://aipatterns.dev/design-patterns/command.md) vs [Strategy](https://aipatterns.dev/design-patterns/strategy.md): a command represents a request to run later; a strategy represents a way to compute now.

## Agent checklist

- [ ] You can state the pain in one sentence that names real code.
- [ ] You checked the "Prefer no pattern when" list and none of it applies.
- [ ] You read the chosen pattern's `## Do not use it when` section and none of it applies.
- [ ] At least three variants exist, or a third is concretely planned.
- [ ] A test exists, or will exist, that is easier to write after the change.
- [ ] Existing tests still pass after you introduce the pattern.
