The Adapter pattern converts the interface of a class into another interface that clients expect — allowing incompatible classes to work together.

Problem

You need to use an existing class, but its interface does not match what your code expects.

Solution

  // Target interface your code expects
interface PaymentProcessor {
    void pay(double amount);
}

// Adaptee — existing incompatible class
class LegacyPaymentGateway {
    public void makePayment(String currency, int cents) {
        System.out.println("Paid " + cents + " " + currency);
    }
}

// Adapter
class LegacyPaymentAdapter implements PaymentProcessor {
    private final LegacyPaymentGateway gateway;

    LegacyPaymentAdapter(LegacyPaymentGateway gateway) {
        this.gateway = gateway;
    }

    @Override
    public void pay(double amount) {
        gateway.makePayment("USD", (int) (amount * 100));
    }
}

// Client
PaymentProcessor processor = new LegacyPaymentAdapter(new LegacyPaymentGateway());
processor.pay(49.99);
  

Object Adapter vs Class Adapter

Object Adapter Class Adapter
Uses composition Uses inheritance
More flexible Cannot adapt subclasses
Preferred in Java Limited by single inheritance

Java Examples

  // Arrays.asList adapts array to List interface
List<String> list = Arrays.asList(array);

// InputStreamReader adapts bytes to characters
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);

// Spring MVC HandlerAdapter adapts various controller types
  

When to Use

  • Integrate third-party libraries with incompatible interfaces
  • Wrap legacy code for new systems
  • Create reusable classes that cooperate with unrelated classes

Best Practices

  • Use object adapter (composition) in Java
  • Keep the adapter thin — only translate interfaces, do not add business logic
  • Consider whether a facade (simpler interface) is more appropriate
  • In modern code, lambda wrappers can serve as simple adapters