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 dynamically

Interactive Adapter Pattern SimulatorLIVE PLAYGROUND

Interact with the controls below to see how this design pattern executes in memory at runtime.

Category: Structural
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

ParticipantRole & ResponsibilityType
Client InterfaceDefines the domain protocol your app usesinterface
Adaptee (3rd Party)Existing incompatible classclass
AdapterImplements Client Interface and delegates to Adapteeclass
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.