DEV Community

Syed Yakoob Shiraz
Syed Yakoob Shiraz

Posted on

Adapter Pattern – The Translator Of Code

📘 Why This Blog?

I once tried plugging a new payment system into my existing wallet app.

Sounds simple, right?

Except the new payment API looked nothing like the one I already had.

I ended up rewriting half my code just to make it fit. 🤯

That’s when the Adapter Pattern walked in—like a translator between two worlds.

This blog is my no-fluff, real-world breakdown of the Adapter Pattern—the way I wish someone had explained it when I was pulling my hair out.


📖 What is the Adapter Pattern?

The Adapter Pattern lets you make incompatible interfaces work together.

In simple terms: You wrap one class inside another to make it “look like” what your code expects.

Like an electric plug adapter—it doesn’t change the electricity, just the shape of the socket.


🔍 Spotting an Adapter

You're probably in Adapter territory if:

  • You’re integrating with an external API or legacy system
  • You find yourself writing conversion code over and over
  • Your new class just won’t “fit” the interface your system expects

🧪 Code Example – Payment Gateway Adapter

Step 1: The Expected Interface

public interface IPaymentProcessor {
    void pay(int amount);
}
Enter fullscreen mode Exit fullscreen mode

Step 2: An Existing Payment Gateway (Incompatible)

public class FancyPaySDK {
    public void makeTransaction(double valueInDollars) {
        System.out.println("Transaction of $" + valueInDollars + " done via FancyPay");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: The Adapter

public class FancyPayAdapter implements IPaymentProcessor {
    private final FancyPaySDK fancyPay;

    public FancyPayAdapter(FancyPaySDK fancyPay) {
        this.fancyPay = fancyPay;
    }

    @Override
    public void pay(int amount) {
        // Assume 1 unit = 1 dollar for simplicity
        fancyPay.makeTransaction(amount);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Client Code

public class Checkout {
    private final IPaymentProcessor processor;

    public Checkout(IPaymentProcessor processor) {
        this.processor = processor;
    }

    public void completeOrder(int amount) {
        processor.pay(amount);
    }
}
Enter fullscreen mode Exit fullscreen mode
public class Main {
    public static void main(String[] args) {
        FancyPaySDK fancyPay = new FancyPaySDK();
        IPaymentProcessor adapter = new FancyPayAdapter(fancyPay);

        Checkout checkout = new Checkout(adapter);
        checkout.completeOrder(100); // $100 via FancyPay
    }
}
Enter fullscreen mode Exit fullscreen mode

⚠ Important Notes

  • You’re not changing FancyPaySDK
  • You're wrapping it in an Adapter to fit the IPaymentProcessor interface
  • This keeps your client code clean and decoupled

🤔 When to Use Adapter

  • Integrating with legacy systems or third-party libraries
  • Making two interfaces compatible without modifying either
  • Bridging between new and old code in large systems

✅ Benefits

  • Helps reuse existing code without modifying it
  • Promotes interface-driven design
  • Makes integration painless and clean

❗ Caution

  • Too many adapters can lead to complexity and confusion
  • If you're writing lots of tiny adapters, rethink your abstractions
  • Avoid adapting things that should be redesigned instead

🔗 More Examples

👉 Adapter Pattern on GitHub


🥵 TL;DR

The Adapter Pattern is like a plug converter.

Instead of:

“I’ll rewrite my system to match this new class…”

You say:

“I’ll wrap it so it fits my system.”

Adapt. Don’t force. Write clean bridges between old and new.

Be the Integrator, not the Imitator. ⚙️

Made with ❤️ by syedyshiraZ

Top comments (0)