The Adapter Pattern - Making Interfaces Work Together

Site Admin · 11 Sep 2026 · 8 views

The Adapter Pattern

The Adapter pattern translates one interface into another so that classes that could not work together can collaborate. It sits between a client that expects a certain interface and a service that speaks a different one, converting calls so both sides stay unchanged.

The Problem: Mismatched Interfaces

Your application expects analysts to read CSV files, but the analytics library you purchased only understands JSON. Rewriting the library is risky, and rewriting every analyser is wasteful. An adapter bridges the two: it presents a CSV-friendly interface while converting each request into the JSON the library understands.

+---------------+    analyse()    +----------------+
|   Client      | ---------------> |  CsvAnalysis  |
|  (expects CSV)|                 |   (adapter)   |
+---------------+                 +----------------+
                                           |
                                           >   parseJson()
                                   +------------------+
                                   | JsonAnalyticsLib |
                                   |  (third-party)  |
                                   +------------------+

The client depends on the adapter. The adapter depends on the library. No existing class needs to change.

A Java Adapter

First define the interface your code already wants.

public interface CsvParser {
    List<String> parseCsv(String content);
}

The client happily talks to any CsvParser. Now adapt the JSON library to satisfy that interface.

public class JsonToCsvAdapter implements CsvParser {
    private final JsonAnalyticsLib library;

    public JsonToCsvAdapter(JsonAnalyticsLib library) {
        this.library = library;
    }

    public List<String> parseCsv(String content) {
        String json = library.toJson(content);
        return library.splitRows(json);
    }
}

Walkthrough: the adapter implements the interface the client knows. It holds the third-party library inside. When parseCsv() is called, the adapter translates: it pushes CSV into the library, pulls back JSON rows, and returns them in the exact type the client expects. The library never learns about CSV, and the client never learns about JSON.

Object vs. Class Adapters

The version above is an object adapter - it uses composition, so it works even when the library is final or already extends another class. Java cannot do true multiple inheritance, so a class adapter that extends the library and implements the interface is rare in Java. Prefer composition (an object adapter) whenever you can.

public class Usage {
    public static void main(String[] args) {
        JsonAnalyticsLib lib = new JsonAnalyticsLib();
        CsvParser adapter = new JsonToCsvAdapter(lib);
        List<String> rows = adapter.parseCsv("a,b,c\nd,e,f");
        System.out.println(rows);
    }
}

The rest of the program only sees a CsvParser. Swapping the underlying library later means writing a new adapter, not touching client code.

A Real-World Case

Legacy systems are the classic territory for adapters. A bank keeps a 15-year-old account service with its own odd API. The new mobile app expects a modern AccountService. An AccountAdapter maps the modern methods onto the legacy calls, so the app ships on schedule and the old mainframe is left untouched. Power adapters work the same way: a plug shape in one country fits a socket in another only because something small stands between them.

Key Points

  • Adapter lets two incompatible interfaces collaborate without changes on either side.
  • It wraps one object and converts calls to a different shape.
  • Object adapters use composition and fit Java better than class adapters.
  • Add an adapter when you integrate third-party or legacy code.
  • Adapters protect the rest of your code from library-specific APIs.
  • If a call converts to nothing and adds no value, the pattern may be unnecessary.
Share this post:

Comments (0)

Please login or register to comment.