Home/Learn/Low Level Design/Adapter Pattern

Adapter Pattern

Beginner
Structural Patterns

Converts the interface of a class into another interface clients expect, enabling incompatible interfaces to work together.

Overview

The Adapter (Wrapper) pattern acts as a bridge between two incompatible interfaces — like a power plug adapter when travelling abroad. There are two variants: Object Adapter (uses composition — wraps an instance of the Adaptee) and Class Adapter (uses multiple inheritance — only possible in languages supporting it; in Java, limited to interface adaptation). Object Adapter is preferred in Java because it is more flexible and does not require changing the Adaptee. Common real-world uses: adapting a third-party payment SDK to your PaymentGateway interface, adapting legacy XML APIs to a modern JSON API, java.util.Arrays.asList() adapting an array to a List.

Object Adapter (Composition)

The Adapter class implements the Target interface and holds a reference to the Adaptee. It delegates Target method calls to corresponding Adaptee methods, translating parameters and return types as needed.

Java — Object Adapter (Stripe SDK to PaymentGateway)
// Target interface — what the client expects
public interface PaymentGateway {
    boolean charge(String userId, double amountInRupees);
    boolean refund(String transactionId);
}

// Adaptee — third-party Stripe SDK (incompatible interface, cannot be changed)
public class StripeSdk {
    public StripeResponse createCharge(StripeChargeRequest request) {
        System.out.println("Stripe: charging " + request.getAmountInCents() + " cents");
        return new StripeResponse("ch_123", true);
    }

    public StripeResponse reverseCharge(String chargeId) {
        System.out.println("Stripe: reversing charge " + chargeId);
        return new StripeResponse(chargeId, true);
    }
}

// Supporting Stripe DTOs
class StripeChargeRequest {
    private long amountInCents;
    private String currency;
    public StripeChargeRequest(long amountInCents, String currency) {
        this.amountInCents = amountInCents;
        this.currency = currency;
    }
    public long getAmountInCents() { return amountInCents; }
}

class StripeResponse {
    private final String chargeId;
    private final boolean success;
    public StripeResponse(String chargeId, boolean success) {
        this.chargeId = chargeId; this.success = success;
    }
    public boolean isSuccess() { return success; }
    public String getChargeId() { return chargeId; }
}

// Adapter — wraps Stripe SDK, implements our PaymentGateway interface
public class StripePaymentAdapter implements PaymentGateway {
    private final StripeSdk stripe;  // composition — holds the adaptee

    public StripePaymentAdapter(StripeSdk stripe) {
        this.stripe = stripe;
    }

    @Override
    public boolean charge(String userId, double amountInRupees) {
        // Translate: rupees → paise (INR smallest unit), double → long
        long amountInPaise = Math.round(amountInRupees * 100);
        StripeChargeRequest request = new StripeChargeRequest(amountInPaise, "INR");
        StripeResponse response = stripe.createCharge(request);
        return response.isSuccess();
    }

    @Override
    public boolean refund(String transactionId) {
        StripeResponse response = stripe.reverseCharge(transactionId);
        return response.isSuccess();
    }
}

// Client code — depends only on PaymentGateway, unaware of Stripe
public class CheckoutService {
    private final PaymentGateway gateway;

    public CheckoutService(PaymentGateway gateway) { this.gateway = gateway; }

    public void checkout(String userId, double amount) {
        boolean success = gateway.charge(userId, amount);
        System.out.println("Payment " + (success ? "succeeded" : "failed"));
    }
}

// Wiring
CheckoutService service = new CheckoutService(new StripePaymentAdapter(new StripeSdk()));
service.checkout("user-42", 999.0);

Java Standard Library Examples

The Java library is full of Adapters. Arrays.asList() adapts a fixed-length array to a List. Collections.enumeration() adapts an Iterator to an Enumeration. InputStreamReader adapts a byte-stream InputStream to a character-stream Reader.

Java — Adapter examples in standard library
// Arrays.asList — adapts T[] → List<T>
String[] arr = {"Java", "LLD", "Design"};
List<String> list = Arrays.asList(arr);

// InputStreamReader — adapts InputStream (bytes) → Reader (chars)
InputStream byteStream = new FileInputStream("data.txt");
Reader charReader = new InputStreamReader(byteStream, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(charReader);

// Collections.enumeration — adapts Iterator → Enumeration (legacy API)
List<String> names = List.of("Alice", "Bob");
Enumeration<String> enumeration = Collections.enumeration(names);

// Your own: adapt java.util.logging.Logger to your Logger interface
public interface AppLogger {
    void info(String msg);
    void error(String msg, Throwable t);
}

public class JulLoggerAdapter implements AppLogger {
    private final java.util.logging.Logger logger;
    public JulLoggerAdapter(String name) {
        this.logger = java.util.logging.Logger.getLogger(name);
    }
    @Override public void info(String msg) { logger.info(msg); }
    @Override public void error(String msg, Throwable t) { logger.log(Level.SEVERE, msg, t); }
}

Key Points to Remember

  • 1Adapter converts an existing interface into one a client expects — "make it fit".
  • 2Object Adapter (composition) is preferred in Java over Class Adapter (inheritance).
  • 3Adapter pattern is used when integrating third-party libraries without modifying them.
  • 4Arrays.asList(), InputStreamReader, and Collections.enumeration() are canonical Java Adapter examples.
  • 5Adapter and Decorator both wrap objects — Adapter changes the interface; Decorator keeps it the same.

Interview Questions

Sign in to ask Aria
1

What is the difference between Adapter and Decorator patterns?

MediumAmazon
2

What is the difference between Object Adapter and Class Adapter?

EasyGoogle
3

Give three examples of the Adapter pattern in the Java standard library.

EasyMicrosoft
4

How would you use the Adapter pattern to integrate a new payment SDK?

MediumFlipkart

Ask Aria about Adapter Pattern

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…