0 XP · 0 scenes

Adapter

Make an incompatible interface fit the one you expect
The problem

Your checkout calls payer.pay(rupees), but the old payment gateway offers make_payment(paise) and cannot be changed.

The idea

Write a small wrapper that implements the interface your code expects and, inside, translates each call into what the strange class understands.

Reach for it when

You must use a class whose interface you cannot change

1

The picture from life

You travel from India to Europe with a three-pin charger and find a two-pin socket. You do not rebuild the hotel or the charger; you plug a small travel adapter between them. The charger sees the shape it knows, the wall sees the shape it knows.

2

The problem

What goes wrong when you do not use it.

Your checkout calls payer.pay(rupees), but the old payment gateway offers make_payment(paise) and cannot be changed. If you call the gateway directly, its odd shape leaks into every place that takes money.

✗ Before
Cartint(rupees * 100)Subscriptionint(rupees * 100)OldGatewaymake_payment(paise)make_paymentmake_payment
  • calls / uses
Every caller repeats the rupees to paise conversion and knows the odd gateway API.
Reach for it when
  • You must use a class whose interface you cannot change
  • You want one interface over several similar third-party libraries
  • Legacy code must keep working with new code
3

The idea

How the pattern fixes it.

Write a small wrapper that implements the interface your code expects and, inside, translates each call into what the strange class understands.

✓ After
checkout()«interface»Payerpay(rupees)PaymentAdaptergatewaypay(rupees)OldGatewaymake_payment(paise)pay()wraps
  • implements
  • has a / holds
  • calls / uses
The adapter speaks the new language outside and the old one inside. Callers never change.

Who is who

Payer (target)
The interface your code wants: pay(rupees).
OldGateway (adaptee)
The existing class with the different method.
PaymentAdapter
Implements Payer, holds an OldGateway and converts calls.

Build it in steps

  1. 1Write down the interface your code expects.
  2. 2Create the adapter implementing it.
  3. 3Hold the strange object inside the adapter.
  4. 4Translate arguments and results in each method.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

checkoutPaymentAdapterOldGateway1pay(5)2int(5 * 100)3make_payment(500)4'paid 500 paise'5'paid 500 paise'
Step 1/5

checkout uses the interface it knows: pay(rupees).

pay(5)
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class OldGateway:
    def make_payment(self, paise):
        return f"paid {paise} paise"


class PaymentAdapter:                       # the interface the app expects: pay(rupees)
    def __init__(self, gateway):
        self.gateway = gateway

    def pay(self, rupees):
        return self.gateway.make_payment(int(rupees * 100))


def checkout(payer, rupees):
    return payer.pay(rupees)


def demo():
    return checkout(PaymentAdapter(OldGateway()), 5)

What you gain

  • Reuse old or foreign code without editing it
  • Conversion lives in one place

What it costs

  • One more layer to read
  • If you own the code, changing the interface directly may be simpler

You have already met it in

  • Arrays.asList adapts an array to a List
  • InputStreamReader adapts bytes to characters
  • Wrappers around payment or SMS vendors

Often mixed up with

  • FacadeAdapter changes the shape of one interface; Facade offers a simpler front for a whole subsystem.
  • ProxyA Proxy keeps the same interface; an Adapter changes it.
6

Make it stick

Your app wants a Logger with log(text). Adapt a library whose class has write(level, message, timestamp) so the app code does not change.

Confidence