Adapter Design Pattern in Java

In this article we will look into Adapter Design Pattern in java and try to understand what problem it solves and its practical use case.
Adapter design pattern is one of the structural design pattern and is used to make two unrelated interfaces work together. The object that joins these unrelated interfaces is called an Adapter.

Adapter Design Pattern in Java
Adapter Design Pattern in Java

Introduction

Adapter design acts as a bridge between two interfaces, making them compatible and enabling them to work seamlessly. This pattern is useful when you need to integrate existing code or libraries that have different interfaces with your codebase without making significant modifications.
So, we can say like, it tries to solve the problem of making two (or more) incompatible classes compatible by using an intermediate class that implements a common interface. It allows objects of incompatible interfaces to collaborate.

Understanding the Adapter Pattern

Key components of The Adapter Pattern

  • Client: This is the Class, that uses the Target interface, and wants to connect to multiple sources.
  • Target: An interface or contract that defines a single API the Client will interact with.
  • Adaptee: This is the class or interface that client wants to connect with the Target Interface. It is the existing code or component with an incompatible interface.
  • Adapter: The Adapter is a class that implements the Target Interface and wraps an instance of the Adaptee, translating calls between them.

Two Way of Adapter Pattern

While implementing Adapter pattern, there are two approaches – class adapter and object adapter – however both these approaches produce same result.

Class Adapter – This form uses java inheritance and extends the source interface. i.e. the Adapter class extends both the Target interface and the Adaptee class.

Object Adapter – This form uses Java Composition and adapter contains the source object. i.e. the Adapter class implements the Target interface and contains an instance of the Adaptee class.

Adapter Design Pattern Implementation

Let’s take an example of payment support provided by different UPI provider, like PayTM, PhonePe. Each payment gateway has its own unique interface and methods for processing payments, s lets discusses it in details.

Step 1: Adapter interface

Let’s define common interface with a method signature in it, that need to implement by different provider.

public interface UPIGateway {
    void processPayment(double amount);
}

Step 2: Create Payment Gateway Adapters

We will create adapter classes for each specific payment gateway provider like PayTM, PhonePe.

PayTM Adopter:
public class PayTMAdapter implements UPIGateway {
private PayTM paymentGateway;

public PayTMAdapter(PayTM paymentGateway) {
     this.paymentGateway = paymentGateway;
}

@Override
public void processPayment(double amount) {
     // Convert our application's method to PayTM's method
       paymentGateway.makePayment(amount);
      }
}
PhonePe Adapter

Similarly, we will create an adapter for the PhonePe payment gateway

public class PhonePeAdapter implements UPIGateway {
  private PhonePe paymentGateway;

  public PhonePeAdapter(PhonePe paymentGateway) {
     this.paymentGateway = paymentGateway;
  }

@Override
  public void processPayment(double amount) {
   // Convert our application's method to PhonePe's method
   paymentGateway.charge(amount);
  }
}

These adapter call will take instance of respective gateways and call proceedPayment().

Step 3: Implement Concrete Payment Gateway Providers

In this step we will provide gateways implementation.

PayTM :

public class PayTM {
  public void makePayment(double amount) {
   // PayTM payment processing logic
     System.out.println("Paid $" + amount + " via PayTM.");
  }
}

PhonePe:

public class PhonePe {
  public void charge(double amount) {
   // PhonePe payment processing logic
     System.out.println("Charged $" + amount + " using PhonePe.");
  }
}

Step 4: Client Code

Let’s use all the component that we already define in our client program.

public class PaymentApp {
public static void main(String[] args) {
   UPIGateway payTMGateway = new PayTMAdapter(new PayPM());
   UPIGateway phonePeGateway = new PhonePeAdapter(new PhonePe());
   double amount = 15000.0;
   // Process payments using different payment gateways
   payTMGateway.processPayment(amount);
   phonePeGateway.processPayment(amount);
  }
}

Adapter Design Pattern Benefits

  • Enables collaboration between two or more incompatible interfaces
  • It helps you separate the interface or data conversion code from the primary business logic of the program.
  • You can introduce new types of adapters, without having to change your code on the Client class.

Adapter Design Pattern Drawbacks

  • Can introduce additional complexity if not used judiciously.
  • May result in performance overhead due to the translation between interfaces.
  • Increases the number of classes and complexity in the codebase.

You may find other post on different topic that might be helpful, Please have a look

  1. Factory design pattern in Java
  2. Builder design pattern
  3. Abstract class and Interface
  4. Java 8 new feature
  5. Arrays.asList() and List.of()

 

 

Leave a Comment