Skip to content

Structural Patterns#

flowchart LR
  C[Client]
  A([Adapter])
  D([Decorator])
  F([Facade])
  P([Proxy])
  X[Subject / Underlying]
  C --> A --> X
  C --> D --> X
  C --> F --> X
  C --> P --> X

  classDef p fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
  classDef s fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
  classDef r fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
  class C p;
  class A,D,F,P s;
  class X r;

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class C client;
    class A,D,F,P,X service;
Decorator pattern UML class diagram
Source: Wikimedia Commons. CC BY-SA / public domain.

These patterns are about composing objects: how to combine, wrap, adapt, or simplify existing types.

Adapter - make an incompatible interface fit#

classDiagram
  class Client
  class Target {
    <<interface>>
    +request()
  }
  class Adapter {
    -adaptee: Adaptee
    +request()
  }
  class Adaptee {
    +specificRequest()
  }
  Client --> Target
  Target <|.. Adapter
  Adapter --> Adaptee : delegates

Wraps an existing class so it conforms to a different interface. Bridges to legacy / third-party APIs.


Decorator - wrap with extra behaviour without subclassing#

classDiagram
  class Component {
    <<interface>>
    +operation()
  }
  class ConcreteComponent
  class Decorator {
    -wrapped: Component
    +operation()
  }
  class LoggingDecorator
  class CachingDecorator
  Component <|.. ConcreteComponent
  Component <|.. Decorator
  Decorator <|-- LoggingDecorator
  Decorator <|-- CachingDecorator
  Decorator --> Component : wraps

Each decorator adds a behaviour and forwards to the wrapped instance. Stackable. Java BufferedReader(new FileReader(...)) is the canonical example.


Facade - one simplified interface in front of a subsystem#

classDiagram
  class Client
  class Facade {
    +simple()
  }
  class SubA
  class SubB
  class SubC
  Client --> Facade
  Facade --> SubA
  Facade --> SubB
  Facade --> SubC

The subsystem stays open for power users; the Facade exposes the 80% workflow.


Proxy - same interface, controls access#

classDiagram
  class Subject {
    <<interface>>
    +request()
  }
  class RealSubject
  class Proxy {
    -real: RealSubject
    +request()
  }
  Subject <|.. RealSubject
  Subject <|.. Proxy
  Proxy --> RealSubject

Common flavours:

Proxy type Adds
Virtual proxy lazy instantiation of expensive objects
Protection proxy access checks / RBAC
Remote proxy RPC client stub
Caching proxy memoises responses
Smart proxy reference counting, logging

Composite - treat tree of objects as one#

classDiagram
  class Component {
    <<interface>>
    +render()
  }
  class Leaf
  class Container {
    -children: Component[]
    +add(Component)
    +render()
  }
  Component <|.. Leaf
  Component <|.. Container
  Container o--> Component

UI widgets, file systems, org charts, ASTs.


Bridge - separate abstraction from implementation#

classDiagram
  class Abstraction {
    -impl: Implementor
  }
  class RefinedAbstraction
  class Implementor {
    <<interface>>
  }
  class ImplA
  class ImplB
  Abstraction <|-- RefinedAbstraction
  Implementor <|.. ImplA
  Implementor <|.. ImplB
  Abstraction --> Implementor

Use when both the abstraction and the implementation can vary independently (e.g. shapes × rendering backends).


Flyweight - share intrinsic state across many small objects#

When you have millions of small objects with mostly-identical state, share the intrinsic bits (font glyphs, terrain tiles) and keep only extrinsic state (position, rotation) per instance.

Where these show up in this site#

  • API gateway / proxy: Proxy pattern.
  • Distributed cache (cache-aside): Caching Proxy.
  • CDN: Caching Proxy + Reverse Proxy.
  • Logger framework: Decorator (adding format/level/filter chains).
  • Online whiteboard / Google Docs: Composite for nested shapes / block trees.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD CDN edge caching for static assets cdn
HLD API gateway / BFF single ingress, auth, rate limit, routing api-gateway
HLD Cache strategies cache-aside, read/write-through, eviction caching-strategies
LLD OOP pillars encapsulation, abstraction, inheritance, polymorphism oop-pillars
LLD Structural patterns Adapter, Decorator, Facade, Proxy, Composite structural-patterns

Quick reference#

Quick chooser#

You want to... Pick
Use a class with the wrong interface Adapter
Add behaviour to one instance without subclassing Decorator
Hide a complex subsystem Facade
Control access / cache / log calls Proxy
Treat individuals and groups uniformly Composite
Decouple abstraction from implementation Bridge
Reduce memory of many similar small objects Flyweight

Adapter vs Bridge#

Adapter is reactive - bridges an existing incompatibility. Bridge is proactive - designed in advance so abstraction and implementation can evolve separately.

Decorator vs Proxy#

  • Decorator adds behaviour, often visible (e.g. logging).
  • Proxy controls or replaces access, often transparent (caller can't tell it's there).

Facade vs API gateway#

The API Gateway is a Facade applied at the service-mesh level.

Refs#

  • GoF book chapters on structural patterns.
  • Java java.io package - half of it is decorators + adapters.
  • Spring AOP - Proxy at runtime, code-generated.

FAQ#

What are structural design patterns?#

They are patterns that compose objects into larger structures. Adapter, Decorator, Facade, Proxy, Composite, Bridge, and Flyweight all sit in this category.

What is the difference between Adapter and Decorator?#

Adapter changes an object's interface so a client can use it. Decorator keeps the same interface and adds behaviour. Both wrap but with different goals.

When should I use the Facade pattern?#

Use Facade to present a simple unified API over a complex subsystem. It is ideal when callers only need a few high-level operations and you want to hide the internals.

What is the Flyweight pattern good for?#

Flyweight shares immutable state across many objects to reduce memory. Text editors share glyph metadata across millions of characters using this trick.

How is a Proxy different from a Decorator?#

A Proxy controls access (lazy loading, security, remote calls) while exposing the same interface. A Decorator enhances behaviour. The shape is similar; the intent differs.

  • Behavioral Patterns: structural and behavioral patterns are typically applied together in the same design
  • Creational Patterns: factories and builders create the objects that structural patterns compose
  • SOLID Principles: OCP and ISP motivate Decorator, Adapter, and Facade design choices

Further reading#

Curated, high-credibility sources for going deeper on this topic.