Adapter Pattern
Adapter Pattern
Convert the interface of a class into another interface clients expect — letting incompatible interfaces work together retrospectively.
Intent
The Adapter wraps an existing Adaptee class and exposes a Target interface that the client already expects. Because the client depends on the Target interface, and the Adaptee exists independently with its own interface, the Adapter is the translation layer that makes them collaborate without modifying either party.
Two variants exist: the Object Adapter uses composition (the Adapter holds a reference to the Adaptee) — this is the preferred approach in Java and TypeScript because it does not require multiple inheritance. The Class Adapter uses multiple inheritance (Adapter extends both Target and Adaptee) — this is not applicable in Java or TypeScript, which do not support multiple class inheritance.
When NOT to Use
- You control both classes — change one interface directly instead of adding indirection
- The interface difference is trivial (one-line translation) — inline the mapping without a named class
- A Bridge or Facade already covers the requirement — see "Related Concepts"
When to Use
- Integrating a third-party or legacy class whose interface cannot be changed
- Making independently-developed classes collaborate despite interface mismatch
How It Works
Participants: Target (the interface the client expects), Adaptee (the existing class with an incompatible interface), Adapter (implements Target; holds a reference to Adaptee and delegates to it), Client (calls methods on the Target interface; has no knowledge of the Adaptee).
The delegation chain: Client calls target.request() → Adapter translates that call → Adapter calls adaptee.specificRequest() → Adapter returns the result to Client. The client and adaptee never interact directly.
Class Diagram
classDiagram
class Target {
<<interface>>
+request()
}
class Adaptee {
+specificRequest()
}
class ObjectAdapter {
-adaptee : Adaptee
+request()
}
class ClassAdapter {
+request()
+specificRequest()
}
Target <|.. ObjectAdapter : implements
ObjectAdapter o-- Adaptee : wraps
Target <|.. ClassAdapter : implements
Adaptee <|-- ClassAdapter : inherits
note for ObjectAdapter "Object Adapter: composition\n(preferred — works at runtime)"
note for ClassAdapter "Class Adapter: inheritance\n(needs multiple inheritance)"
TypeScript Example
// Adapter — TypeScript (Object Adapter)
// Source: GoF Design Patterns, p.139
interface Target {
request(): string;
}
class Adaptee {
specificRequest(): string { return "Adaptee response"; }
}
class Adapter implements Target {
constructor(private adaptee: Adaptee) {}
request(): string {
return this.adaptee.specificRequest();
}
}
// Usage — client works with Target interface, never knows about Adaptee
const adapter = new Adapter(new Adaptee());
adapter.request();Java Example
// Adapter — Java (Object Adapter, preferred over Class Adapter for flexibility)
// Source: GoF Design Patterns, p.139
interface Target { String request(); }
class Adaptee { public String specificRequest() { return "Adaptee response"; } }
class Adapter implements Target {
private final Adaptee adaptee;
Adapter(Adaptee a) { this.adaptee = a; }
@Override public String request() { return adaptee.specificRequest(); }
}Related Concepts
| Pattern | Relationship |
|---|---|
| Bridge-Pattern | Bridge separates abstraction/implementation prospectively (designed upfront); Adapter reconciles two existing incompatible interfaces retrospectively |
| Facade-Pattern | Facade creates a new simplified interface; Adapter converts to a specific existing interface the client already expects |
| Factory-Method-Pattern | Creational pattern that produces the objects an Adapter may wrap |
Related Architecture Patterns
- Hexagonal-Architecture — Every Hexagonal driven adapter IS a GoF Adapter: it translates a port interface (inside the core) to a technology-specific implementation (outside the core).
Sources
- Gamma, Helm, Johnson, Vlissides — Design Patterns, Addison-Wesley, 1994, p.139