# Structural Patterns

> Patterns that combine objects and classes into larger structures while keeping each part replaceable and its interface small.

- kind: category
- category: design-patterns
- canonical: https://aipatterns.dev/design-patterns/structural
- inspired-by: https://refactoring.guru/design-patterns/structural-patterns

## What these patterns solve

Structural patterns deal with how pieces fit together. One interface doesn't match another, a subsystem is too wide to call directly, a feature must be layered on without editing the class, or millions of small objects use too much memory. Each pattern puts a wrapper, a tree or a shared object between the caller and the real work.

**Most structural patterns look the same in code: an object that holds another object and forwards calls to it. Tell them apart by intent, not by shape.**

## Members

- [Adapter](https://aipatterns.dev/design-patterns/adapter.md): converts one interface into the interface a caller expects, such as wrapping a vendor SDK behind your own port.
- [Bridge](https://aipatterns.dev/design-patterns/bridge.md): splits an abstraction from its implementation so both can vary independently, avoiding a class for every combination.
- [Composite](https://aipatterns.dev/design-patterns/composite.md): treats a single item and a tree of items through the same interface, as with files and folders.
- [Decorator](https://aipatterns.dev/design-patterns/decorator.md): wraps an object to add behavior (caching, retries, logging) while keeping its interface.
- [Facade](https://aipatterns.dev/design-patterns/facade.md): gives a complex subsystem one small, task-oriented entry point.
- [Flyweight](https://aipatterns.dev/design-patterns/flyweight.md): shares the immutable part of many similar objects to cut memory use.
- [Proxy](https://aipatterns.dev/design-patterns/proxy.md): stands in for another object with the same interface to control access: lazy loading, remote calls or permission checks.

## How to choose within this category

- **The interface is wrong and you don't own the other side:** use [Adapter](https://aipatterns.dev/design-patterns/adapter.md).
- **The interface is fine but you want extra behavior around calls:** use [Decorator](https://aipatterns.dev/design-patterns/decorator.md). If the extra behavior is about *whether or when* the real object is reached, it's a [Proxy](https://aipatterns.dev/design-patterns/proxy.md). In languages with higher-order functions, wrapping a single function (`withRetry(fetchInvoice)`) often replaces a decorator class.
- **The subsystem is too big for most callers:** use [Facade](https://aipatterns.dev/design-patterns/facade.md). It adds a simpler interface; it doesn't translate an incompatible one.
- **You have nested parts and wholes:** use [Composite](https://aipatterns.dev/design-patterns/composite.md). A recursive union type with pattern matching can replace it in TypeScript, Rust or modern Java.
- **Two dimensions vary and subclasses multiply (`PdfInvoice`, `HtmlInvoice`, `PdfReceipt`, ...):** use [Bridge](https://aipatterns.dev/design-patterns/bridge.md).
- **Profiling shows memory pressure from duplicated state:** use [Flyweight](https://aipatterns.dev/design-patterns/flyweight.md). Don't apply it without a measurement.

## Prefer no pattern when

- You control both sides of an interface mismatch. Change one side instead of adding an adapter.
- A wrapper would forward every call unchanged. That's a [Middle Man](https://aipatterns.dev/refactoring/smells/middle-man.md).
- Only one combination of features ever exists. Compose it directly.
