Adapter Pattern

What is the Adapter pattern?

Adapter means: wrap a class with one interface so it looks like a different interface your code already expects.

You keep both sides unchanged. The adapter sits in the middle and translates calls from the shape the caller uses into the shape the existing class actually understands.

Three roles show up every time:

  1. Target — the interface your code already calls.
  2. Adaptee — the existing class with a different, incompatible interface.
  3. Adapter — the new class that implements Target and calls Adaptee underneath.

The problem it solves

Your code expects one interface for playing media. A third-party library exposes a different one, with different method names.

AdvancedMediaPlayer has no play(audioType, fileName) method. You cannot easily rewrite a library you do not own, and you do not want its method names spreading through your app. Adapter bridges the two without touching either.


The object adapter

The common form uses composition. The adapter holds the adaptee and implements the target interface, forwarding each call to the right method underneath.

AudioPlayer only ever calls play. Whether that call is handled directly or routed through MediaAdapter is invisible to the caller.


The class adapter (less common)

Instead of holding the adaptee as a field, a class adapter inherits from it and implements the target interface on top.

This locks the adapter to one adaptee, chosen at compile time, and it inherits everything the adaptee exposes. Prefer the object adapter unless you have a specific reason to reach for inheritance.


Worked example: a legacy payment system

A legacy payment method with its own signature, sitting next to a newer interface your app now standardizes on.

Both processors are constructed and called the same way. One happens to route through an adapter and an old system underneath; the caller cannot tell.


When it helps

Reach for Adapter when you are integrating with something you cannot change — a third-party library, a legacy module, an external API — and its interface does not match what your code expects.

It also helps during a gradual migration: wrap the old implementation in an adapter that satisfies the new interface, ship the new interface everywhere, and swap the real implementation later without anyone noticing.

The signal to look for is a shape mismatch, not a missing feature. Adapter does not add capability — the adaptee could already do the job.


When it hurts

If you own both sides of the interface, just change the interface directly instead of adding a translation layer to maintain forever. A pile of adapters is often a sign an interface needs redesigning, not patching around.

Watch for adapters that quietly grow business logic. An adapter’s job is translation only. Once it starts validating input or branching on business rules, it has become a hidden layer of application logic wearing an adapter’s name.


Practical tips

  • Default to the object adapter (composition) over the class adapter (inheritance).
  • Keep each adapter focused on one adaptee and one target interface.
  • Name and document what is being adapted — a short comment saves the next reader from tracing two classes.
  • Do not confuse Adapter with Facade: Adapter fixes a mismatch between two interfaces; Facade simplifies access to a subsystem whose interfaces already work fine.

Check your understanding

What is Adapter, in one sentence?
A class that translates one interface into another so two otherwise incompatible pieces of code can work together unchanged.

Object adapter vs. class adapter?
Object adapter holds the adaptee as a field and uses composition; class adapter extends the adaptee and uses inheritance. Prefer the object adapter for its flexibility.

When should you reach for Adapter?
When you cannot, or should not, modify one side of a mismatched interface — typically a third-party library, a legacy class, or an external API.

What is the biggest misuse of Adapter?
Letting it accumulate business logic instead of staying a pure translation layer.


What to learn next

Next: Decorator Pattern — add optional behavior to an object without touching its class or creating a mountain of subclasses.