DevNotes
Support
Essential Design Patterns · Chapter 08

Adapter Pattern

Making incompatible interfaces work together — wrapping a legacy payment gateway, object vs class adapters, adapters in the JDK and Spring MVC, and the hexagonal-architecture view.

◷ 4 min read§ 11 sections? 5 interview questions{ } 5 code examples

#Introduction

Purpose: make incompatible interfaces work together.

An adapter converts the interface of an existing class into the interface a client expects — like a travel plug adapter that lets an Indian charger fit a European socket. Neither the client nor the existing class changes.

#Example: Legacy Payment Gateway

The application expects a PaymentProcessor, but the third-party library provides a LegacyPaymentGateway with a different method name:

Java
interface PaymentProcessor {          // what the application expects
    void pay(double amount);
}

class LegacyPaymentGateway {          // what the library provides — can't be changed
    public void makePayment(double amount) {
        System.out.println("Legacy payment: " + amount);
    }
}

The Adapter

Java
class PaymentAdapter implements PaymentProcessor {

    private final LegacyPaymentGateway gateway;

    public PaymentAdapter(LegacyPaymentGateway gateway) {
        this.gateway = gateway;
    }

    @Override
    public void pay(double amount) {
        gateway.makePayment(amount);   // translate the call
    }
}

Client

Java
public class Main {
    public static void main(String[] args) {
        LegacyPaymentGateway gateway = new LegacyPaymentGateway();
        PaymentProcessor processor = new PaymentAdapter(gateway);

        processor.pay(1000);
    }
}
Output
Legacy payment: 1000.0

(1000 is widened to double, so it prints as 1000.0.)

#Structure

Client
Expected interface — PaymentProcessor
Adapter — PaymentAdapter
Existing / incompatible class — LegacyPaymentGateway
RoleIn the exampleResponsibility
TargetPaymentProcessorThe interface the client expects
AdapteeLegacyPaymentGatewayThe existing class with an incompatible interface
AdapterPaymentAdapterImplements the target and translates calls to the adaptee
ClientMainUses only the target interface

#Real Adapters Do More Than Rename

In practice an adapter often translates data and errors too:

Java
class StripePaymentAdapter implements PaymentProcessor {
    private final StripeClient stripe;

    StripePaymentAdapter(StripeClient stripe) { this.stripe = stripe; }

    @Override
    public void pay(double amount) {
        try {
            long paise = Math.round(amount * 100);                    // unit conversion
            stripe.charges().create(new ChargeRequest(paise, "INR"));  // different request model
        } catch (StripeException e) {
            throw new PaymentFailedException("Payment declined", e);   // translate exceptions
        }
    }
}

#Object Adapter vs Class Adapter

Object adapter (composition)Class adapter (inheritance)
Adapter holds an adaptee instanceAdapter extends the adaptee and implements the target
Works with any subclass of the adapteeTied to one adaptee class
Preferred in JavaPossible only if the adaptee isn't final; uses up the single superclass
Java
// Class adapter — less flexible
class PaymentClassAdapter extends LegacyPaymentGateway implements PaymentProcessor {
    @Override
    public void pay(double amount) {
        makePayment(amount);
    }
}

The example in this chapter is an object adapter — the recommended form (composition over inheritance).

#Adapters in the JDK and Spring

ExampleAdapts
Arrays.asList(array)An array → the List interface
InputStreamReaderA byte InputStream → a character Reader
Collections.enumeration(collection)A Collection → the legacy Enumeration
Spring MVC HandlerAdapterLets DispatcherServlet invoke very different handler types (@Controller methods, HttpRequestHandler, …) through one interface
Spring HttpMessageConverterHTTP bodies ↔ Java objects
JpaVendorAdapterPlugs a JPA provider (Hibernate) into Spring

#Adapters in Hexagonal Architecture

In ports and adapters (hexagonal) architecture, your domain defines ports (interfaces) and the outside world connects through adapters:

PaymentControllerKafkaOrderListener
OrderServicedomain — depends only on ports
StripePaymentAdapterJpaOrderRepository
PaymentPort, OrderRepositoryPortports implemented by adapters

Swapping Stripe for Razorpay means writing a new adapter — the domain doesn't change.

#When to Use

  • Integrating third-party or legacy code whose interface doesn't match yours.
  • Keeping vendor-specific types (SDK classes, exceptions) out of your domain.
  • Migrating gradually from an old API to a new one.

#Interview Questions

Q1What is the Adapter pattern?

A structural pattern that converts the interface of an existing class into another interface that the client expects, so incompatible classes can work together.

Q2What's the difference between an object adapter and a class adapter?

An object adapter wraps an instance of the adaptee (composition); a class adapter extends the adaptee (inheritance). Object adapters are more flexible and preferred in Java.

Q3Adapter vs Decorator?

An adapter changes the interface to a different one; a decorator keeps the same interface and adds behaviour.

Q4Adapter vs Proxy?

A proxy has the same interface as its subject and controls access; an adapter presents a different interface to make an incompatible class usable.

Q5Give examples of Adapter in Java or Spring.

Arrays.asList(), InputStreamReader, and Spring MVC's HandlerAdapter.

#Common Mistakes

  • Leaking adaptee types (vendor exceptions, SDK models) through the adapter.
  • Putting business logic in adapters — they should translate, not decide.
  • Modifying the adaptee or client instead of adapting.
  • Class adapters where composition would be more flexible.

#Key Takeaways

  • Adapter converts one interface into another that the client expects.
  • Neither the client nor the existing class changes.
  • Prefer object adapters (composition).
  • Adapters also translate data formats and exceptions.
  • Adapter changes the interface; Decorator and Proxy keep it.