Design Patterns Adapter

The Adapter pattern connects two incompatible interfaces so they can work together. It acts as a translator — like a travel plug adapter that lets a European device plug into a US power socket. Neither the plug nor the socket changes; the adapter sits in between and makes the connection work.

This pattern belongs to the Structural category. Structural patterns control how classes and objects are assembled into larger structures.

The Everyday Plug Adapter Explained

You buy a laptop in Germany. The charger has a round two-pin European plug. Your hotel room has a flat three-pin US socket. You cannot force the plug in — the shapes are incompatible. A travel adapter accepts the European plug on one side and fits the US socket on the other. The laptop charges. Nothing was re-engineered.

Software adapters work identically. You have existing code (the plug) and a new system (the socket). You write an adapter class that translates calls from one to the other.

Visual Diagram: The Adapter Bridge

+------------------+       +------------------+       +---------------------+
|    Client        |       |    Adapter       |       |  Adaptee (Existing) |
|                  |       |                  |       |                     |
|  calls:          |──────►|  request()       |──────►|  specificRequest()  |
|  target.request()|       |  translates and  |       |  (does the work)    |
|                  |       |  calls adaptee   |       |                     |
+------------------+       +------------------+       +---------------------+

Client knows only "request()".
Adapter knows both sides and bridges the gap.
Adaptee never changes.

Key Participants

Target Interface

The interface the client expects. The client only knows this interface and calls methods on it. It has no knowledge of the adaptee.

Adaptee

The existing class with useful behavior but an incompatible interface. You cannot or do not want to change this class — it may be a third-party library, a legacy system, or code you do not own.

Adapter

The translator class. It implements the Target interface so the client is happy, and internally it calls the Adaptee to do the actual work.

Client

The code that needs a service. It works with the Target interface and never touches the Adaptee directly.

Real Scenario: Integrating a Legacy Payment System

Your e-commerce app uses a PaymentProcessor interface with a pay(amount) method. A new vendor provides a LegacyPaymentGateway class that uses makePayment(dollars, cents) instead. You cannot rewrite the vendor's code.

WHAT YOU HAVE:
  LegacyPaymentGateway
  └── makePayment(dollars, cents)

WHAT YOUR APP EXPECTS:
  PaymentProcessor
  └── pay(amount)

THE PROBLEM:
  App calls pay(19.99) → LegacyGateway has no pay() method → ERROR

THE ADAPTER SOLUTION:
  LegacyPaymentAdapter implements PaymentProcessor
    pay(amount):
      dollars = int(amount)
      cents   = round((amount - dollars) * 100)
      legacy_gateway.makePayment(dollars, cents)

  App calls pay(19.99) → Adapter converts → makePayment(19, 99) → 

Code Walkthrough in Python

Step 1 — The Target Interface

class PaymentProcessor:
    def pay(self, amount):
        raise NotImplementedError

Step 2 — The Adaptee (existing, incompatible class)

class LegacyPaymentGateway:
    def make_payment(self, dollars, cents):
        print(f"Legacy system charging ${dollars}.{cents:02d}")

Step 3 — The Adapter

class LegacyPaymentAdapter(PaymentProcessor):
    def __init__(self, legacy_gateway):
        self.gateway = legacy_gateway

    def pay(self, amount):
        dollars = int(amount)
        cents = round((amount - dollars) * 100)
        self.gateway.make_payment(dollars, cents)

Step 4 — The Client Uses It Normally

gateway = LegacyPaymentGateway()
processor = LegacyPaymentAdapter(gateway)

processor.pay(19.99)
# Output: Legacy system charging $19.99

The client called pay(19.99) — the same method it uses for every other payment processor. The adapter handled all translation internally.

Two Types of Adapter

Object Adapter (Composition)

+------------------+
| Adapter          |
|------------------|
| adaptee: Adaptee |  ← holds a reference to adaptee
|------------------|
| request()        |  ← calls adaptee.specificRequest()
+------------------+

Adapter CONTAINS the adaptee.
Works in all languages. Most common approach.

Class Adapter (Inheritance)

+------------------+
| Adapter          |
|  extends Target  |
|  extends Adaptee |  ← inherits from both
|------------------|
| request()        |  ← calls inherited specificRequest()
+------------------+

Adapter INHERITS the adaptee.
Only works in languages that support multiple inheritance (C++).
Not available in Python (cleanly) or Java.

Object Adapter is the standard choice in most modern languages.

Diagram: Object Adapter vs Class Adapter

OBJECT ADAPTER                      CLASS ADAPTER
                                    
Client                              Client
  │                                   │
  ▼                                   ▼
Target ◄──── Adapter                Target ◄──── Adapter
              │                                   │
              │ holds reference                   │ inherits
              ▼                                   ▼
           Adaptee                             Adaptee

When to Use the Adapter Pattern

Use Adapter When:

  • You want to use an existing class but its interface does not match what you need.
  • You integrate third-party libraries or legacy systems you cannot modify.
  • You want several incompatible classes to work behind a single interface.

Avoid Adapter When:

  • You control both sides of the interface — just change one to match the other directly.
  • The gap between interfaces is so large that the adapter becomes its own complex system — that signals a design problem.

Adapter Pattern in the Real World of Software

SCENARIO                          ADAPTER SOLVES THIS
--------------------------------------------------------------
Reading XML data in a JSON app    XmlToJsonAdapter wraps XML
                                  reader, outputs JSON-like objects

Old SQL database + new ORM        DatabaseAdapter maps ORM calls
                                  to raw SQL queries

Multiple cloud storage APIs       StorageAdapter wraps S3, Azure,
(S3, Azure, GCP)                  GCP behind one interface: upload()

Device drivers in an OS           OS calls standard driver API;
                                  adapter translates to hardware
                                  manufacturer's specific commands

Adapter vs Similar Patterns

+-------------+----------------------------------------------+
| Pattern     | Purpose                                      |
+-------------+----------------------------------------------+
| Adapter     | Makes incompatible interfaces compatible     |
| Facade      | Simplifies a complex system (one clean API)  |
| Decorator   | Adds new behavior to an existing object      |
| Proxy       | Controls access to an object                 |
+-------------+----------------------------------------------+

Adapter changes the INTERFACE.
Decorator changes the BEHAVIOR.
Facade simplifies COMPLEXITY.

Advantages and Disadvantages

Advantages

  • Reuses existing classes without modifying them — preserves working code.
  • Separates interface-translation logic into one dedicated class.
  • Lets different incompatible systems collaborate through a shared interface.

Disadvantages

  • Adds an extra layer — more classes to read and maintain.
  • If many adapters stack on top of each other, tracing a call becomes harder.

Quick Summary

ADAPTER PATTERN — AT A GLANCE

Problem:   Two classes cannot work together because their
           interfaces do not match.
Solution:  Write an Adapter class that wraps the incompatible
           class and translates calls.
Key idea:  Adapter implements the interface the client expects;
           internally it delegates to the adaptee.
Best for:  Third-party integrations, legacy system upgrades,
           multi-platform support.

The Adapter pattern keeps your existing code intact and your new code clean. When two systems need to talk but speak different languages, the adapter becomes the professional interpreter between them.

Leave a Comment