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;
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.iopackage - 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.
Related Topics#
- 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.