Catalog / Structural Patterns / Adapter Pattern
STRUCTURAL

Adapter Pattern

Convert the interface of a class into another interface clients expect.

Intent & Objective

Allow objects with incompatible interfaces to collaborate by providing a wrapper that translates calls from one interface into calls to another.

👥 Real-World Human Analogies & Social Roles
3 Intuitive Scenarios
Travel Plug Converter International Travel

"When you visit another country, your domestic device charger cannot physically fit the foreign wall socket. The adapter bridges electrical pins and voltages so incompatible hardware works together."

Language Translator / Interpreter Human Communication

"Bridges two diplomats who do not speak a common language, translating phrases in real time without forcing either speaker to learn a new language."

Universal Remote Control Consumer Electronics

"Adapts commands to control diverse TV, audio soundbar, and cable box brands through one consistent set of buttons."

The Problem

You need to integrate a third-party analytics library or legacy system whose method names, parameter signatures, and return types conflict with your domain model.

The Solution

Create an Adapter class that implements your standard client interface and wraps the incompatible adaptee object, delegating and transforming method calls.

Key Participants & Architectural Roles

Target Interface
Defines the domain-specific interface that client code expects
Client
Collaborates with objects conforming to the Target interface
Adaptee
The existing legacy or third-party class with an incompatible interface
Adapter
Implements Target and translates requests to the Adaptee

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, Adapter creates an adapter wrapper class inheriting an interface. In Functional Programming, an Adapter is simply a pure function mapping or currying: `f(x) = g(transform(x))` or function composition `(g . f)`.

Advantages

  • ✓ Single Responsibility Principle: separates interface/data conversion from core business logic
  • ✓ Open/Closed Principle: introduces new adapters without breaking existing client code
  • ✓ Reuses existing, battle-tested legacy libraries

Trade-offs

  • ✗ Increases overall code complexity by introducing new interfaces and adapter classes

When to Apply

  • → When you want to use some existing class, but its interface isn’t compatible with the rest of your code
  • → When you want to reuse several existing subclasses that lack some common functionality that can’t be added to the superclass

When to Avoid

  • ! When you have full control over both classes and can simply refactor them directly