Java Omnibus
OOAD & Architecture / GoF patterns / Structural / Adapter Pattern in Java
GoF Structural Java Order Management
GoF Pattern

Adapter is the right structural move when two useful parts do not fit each other’s interface cleanly.

Convert the interface of one class into another interface clients expect so existing code can work with incompatible collaborators.

Intent

What the pattern is trying to do

Convert the interface of one class into another interface clients expect so existing code can work with incompatible collaborators.

Problem

What force creates the need

A useful external or legacy component does the right job but exposes the wrong shape for the rest of the system.

Solution

How the pattern responds

Wrap the mismatched collaborator in an adapter that translates calls and data into the interface your code expects.

Structure

How the moving parts fit together

A client talks to a target interface while the adapter delegates to an adaptee and translates requests and responses between the two models.

Java Example

Java example in the Order Management domain

Adapter Pattern in Java example
package org.javaomnibus.ecommerce.gof.structural;

public interface ShipmentTracker {
    ShipmentStatus track(String shipmentId);
}

public final class LegacyCarrierClient {
    public String lookup(String consignmentNumber) {
        return "IN_TRANSIT";
    }
}

public final class LegacyCarrierAdapter implements ShipmentTracker {
    private final LegacyCarrierClient legacyCarrierClient;

    public LegacyCarrierAdapter(LegacyCarrierClient legacyCarrierClient) {
        this.legacyCarrierClient = legacyCarrierClient;
    }

    @Override
    public ShipmentStatus track(String shipmentId) {
        return ShipmentStatus.valueOf(legacyCarrierClient.lookup(shipmentId));
    }
}
Code Walkthrough

Step by step

  1. The rest of the system depends on ShipmentTracker rather than the legacy client directly.
  2. The adapter isolates shape mismatch at one boundary point.
  3. That keeps the domain model from leaking legacy naming and return formats everywhere.
  4. Adapter is strongest when incompatibility is the real force rather than general simplification.
When To Use

Where this pattern helps

  • When integrating legacy libraries or external APIs with incompatible interfaces
  • When you want boundary translation to stay out of application services and domain code
When Not To Use

When a simpler design is better

  • When you actually need to simplify a subsystem rather than translate one interface into another
  • When adding one more wrapper would hide an already confused integration design
Trade-Offs

What this pattern costs

  • Adds another layer to maintain at the boundary
  • Can hide deeper integration problems if used as a patch over unstable upstream design
Modern Relevance

How this fits today

Adapter remains central in Java because most production systems integrate third-party SDKs, vendor APIs, or internal legacy modules that do not fit the domain model cleanly.

Common Misuse

Where teams get it wrong

Calling any wrapper an adapter is misleading when the real role is simplification, access control, caching, or lazy loading rather than interface translation.

Related Patterns

Compare with nearby choices


What To Read Next