Skip to content

Design Pattern: Adapter (Structural)

Make an incompatible interface fit

Builds on Interfaces and Composition vs Inheritance

Stage 3core2 min read

1. Introduction

Structural design patterns are about how classes and objects are put together into bigger structures. They keep the system easy to change. The Adapter Pattern is a structural pattern for one common problem: two classes that should work together, but whose interfaces (the method names and inputs each one offers) do not match.


2. The Adapter Pattern

The Adapter Pattern lets two classes with different interfaces work together. The adapter is a translator or wrapper placed around an existing class. It turns the interface of that class into the one the client expects.

The Target is the interface the client expects. The Adaptee is the existing class with a different interface. The adapter sits between them and passes each call across.

Real-Life Analogy: The Travel Adapter

Imagine traveling from India to Europe. Your mobile charger (the Adaptee) has an Indian plug, but the wall socket (the Target) is the European format. Instead of buying a new charger, you use a Plug Adapter. It lets the Indian plug fit the European socket. You change neither the socket nor the charger.


3. Class Diagram

In the diagram, CheckoutService (the Client) calls PaymentGateway (the Target). RazorpayAdapter implements PaymentGateway and passes the calls on to RazorpayAPI (the Adaptee).

Loading diagram…

4. Problem & Solution Summary

The Problem

CheckoutService works with any class that implements the PaymentGateway interface. PayUGateway does, so it fits. RazorpayAPI does not. Its method is called makePayment (not pay), and it does not implement your interface. So CheckoutService cannot use it directly.

The Solution

The Adapter Pattern adds the RazorpayAdapter class. It implements your PaymentGateway interface and holds a RazorpayAPI inside. When pay() is called, the adapter calls makePayment() on that object. This is delegation: passing the work to another object. The third-party code stays unchanged.


5. Pros and Cons

ProsCons
Code Reusability: Reuse existing classes (like legacy or 3rd party APIs) without changing their source code.Increased Complexity: Adds an extra layer and more classes to the codebase.
Open/Closed Principle: You can introduce new adapters without breaking existing client code.Potential Performance Overhead: The extra call through the adapter adds a tiny delay.
Single Responsibility: The translation logic is isolated in its own class.Obscured Design: Too many adapters make the design harder to follow.

6. Real-World Use Cases

  1. Payment Gateways: Giving Stripe, PayPal and Razorpay one shared checkout interface, even though their APIs differ.
  2. Logging Frameworks: Creating a wrapper so your app can switch between Log4j, SLF4J, or java.util.logging without changing log calls.
  3. Cloud SDKs: Hiding the vendor behind a common interface, so you can switch between AWS S3 and Google Cloud Storage.

Comparison with Creational Patterns

You used Factory earlier to create objects and Builder to construct them. Adapter is for objects that already exist but don't speak the same language: their method names and inputs do not match.

In this topic

Done with this topic?

How well do you know it?

PreviousCreational Design Patterns: Master Comparison