Back to All Design Patterns
Pattern 5 of 22
Structural PatternBEGINNER7 min deep dive
Adapter Pattern Pattern
Allows objects with incompatible interfaces to collaborate by converting the interface of one object into another.
Real-World Mental Model / Metaphor:
A US-to-UK power plug adapter. The UK wall socket and the US laptop plug are incompatible, but the adapter bridges them without modifying the wall or the laptop.
Interactive Runtime Simulator
Test and tweak inputs dynamicallyInteractive Adapter Pattern SimulatorLIVE PLAYGROUND
Interact with the controls below to see how this design pattern executes in memory at runtime.
Configure Chain Handlers (Toggle Failures):
CHAIN PIPELINE STATUS
Step 1: AuthHandler.check() -> PASSED
Step 2: RateLimitHandler.check() -> PASSED
Step 3: PayloadGuard.check() -> PASSED
The Problem It Solves
Integrating a 3rd-party library, legacy service, or hardware device whose method signatures do not match your application's domain interfaces.
The Architectural Solution
Create an Adapter class that implements the client interface and wraps the incompatible Adaptee instance.
Pattern Structure & Participants
| Participant | Role & Responsibility | Type |
|---|---|---|
| Client Interface | Defines the domain protocol your app uses | interface |
| Adaptee (3rd Party) | Existing incompatible class | class |
| Adapter | Implements Client Interface and delegates to Adaptee | class |
Collaboration Rules:
- Client calls adapter.processPayment(amountInDollars)
- Adapter converts amount to cents and calls adaptee.chargeCreditCard(cents)
Production Code Implementation
Adapter Pattern.java
// 1. Client Domain Interface
public interface PaymentProcessor {
void pay(double dollars);
}
// 2. Incompatible Third-Party Adaptee (e.g. Legacy Stripe SDK)
public class LegacyStripeGateway {
public void executeCharge(long cents, String currency) {
System.out.println("Charged " + cents + " " + currency + " via Legacy Stripe");
}
}
// 3. Adapter
public class StripePaymentAdapter implements PaymentProcessor {
private final LegacyStripeGateway stripeGateway;
public StripePaymentAdapter(LegacyStripeGateway stripeGateway) {
this.stripeGateway = stripeGateway;
}
@Override
public void pay(double dollars) {
// Convert client format (dollars) to adaptee format (cents)
long cents = (long) (dollars * 100);
stripeGateway.executeCharge(cents, "USD");
}
} When to Use:
- •When you want to use an existing class, but its interface does not match the rest of your code.
- •When you want to reuse several existing subclasses that lack common functionality, without subclassing each one.
When to Avoid (Anti-Pattern):
- •When you have full control over the source code of both classes and can simply refactor them directly.
Staff Engineering Interview Insights & Gotchas
- Distinguish Object Adapter (composition - preferred) vs Class Adapter (multiple inheritance).
- Mention Java's `InputStreamReader` as the textbook standard library adapter.