Site icon SpringHow

Adapter Design Pattern

Let’s learn about Adapter Design Pattern with an example in Java.

What is Adapter Design Pattern?

the adapter pattern bridges the gap between two incompatible classes or interface. It is one of the structural design patterns described in the Book of Gang of Four.

For example, take a look at the analogy of android and iPhone charging cables. Out of the box they are not interchangeable. You can’t use a Type-C USB cable on the lightning port of an iPhone. At this point, you are left with two options. That is to get a new lightning cable or get USB-C to Lightning Port adapter. That is exactly what this design pattern tries to achieve.

Let’s convert this analogy in to code.

Implementing Adapter pattern

The adapter pattern has three major players. They are,

  1. Client – A class or program that intends to use different types of Adaptee. In our case, it is the phone.
  2. Adaptee – A class that does a specific work. It doesn’t matter how it does that. In our case, its the different type of chargers.
  3. Adapter – The bridge that converts one type of Adaptee into another. The AndroidToAppleChargerAdapter is an example of this kind.

Client classes

First, lets define both Android and Apple phone implementations. These classes use different charger implementations without any common interface/classes. With the help of adapter pattern, We can write adapter java classes that would convert one type into another.

public class AndroidPhone {

    private AndroidCharger charger;

    public void plugAndroidCharger(AndroidCharger charger) {
        this.charger = charger;
    }

    public void charge() {
        this.charger.charge();
    }
}
Code language: Java (java)
public class ApplePhone {

    private AppleCharger charger;

    public void plugAppleCharger(AppleCharger charger) {
        System.out.println("Charger plugged into your Apple Phone");
        this.charger = charger;
    }

    public void charge() {
        System.out.println("Charging your Apple phone");
        this.charger.charge();
    }
}Code language: Java (java)

As you see here, both these classes require a specific type of chargers. If we supply an android charger to the iPhone, it will be incompatible.

Adaptee classes

Now, Let’s first take a look at the charger classes.

public class AndroidCharger {
    public void chargeAndroidPhones(){
        System.out.println("Charging your phone using Android charger");
    }
}Code language: Java (java)
public class AppleCharger {
    public void chargeApplePhones(){
        System.out.println("Charging your phone using Apple charger");
    }
}Code language: Java (java)

Despite they both solve the same purpose, Their implementations are different(at least the method names don’t match in this example). This is where the adapter design pattern comes into play.

Implementing Adapter class in Java

Let’s say you have an apple phone but with an android charger. In this case, you can use an adapter to convert the android charger into an apple charger. Let’s implement that in code. To begin with, we need an apple charger. So We should extend the AppleCharger class and use the AndroidCharger implementation as its core logic.

 public class AndroidToAppleChargerAdapter extends AppleCharger {
    private final AndroidCharger androidCharger;

    public AndroidToAppleChargerAdapter(AndroidCharger androidCharger) {

        this.androidCharger = androidCharger;
    }

    @Override
    public void chargeApplePhones() {
        System.out.println("You are using a AndroidToAppleChargerAdapter");
        androidCharger.chargeAndroidPhones(); //android charger doesn't know that it is charging an Apple device.
    }
}Code language: Java (java)

As you see here, This implementation is a valid AppleCharger. It even has the chargeApplePhones method that an ApplePhone can use. But internally, it uses an AndroidCharger to perform the actual charging. And infact, the android charger doesn’t even know that it is charging an apple phone.

Adapter Pattern in Action

As we have all the client, adapter and adaptee classes, let’s test this implementation with a sample program.

public class AdapterPatternExample {
    public static void main(String[] args) {
        ApplePhone applePhone = new ApplePhone();
        AndroidCharger androidCharger = new AndroidCharger();
        System.out.println("We have an apple phone and an android charger...!");
        AppleCharger androidToAppleChargerAdapter 
                = new AndroidToAppleChargerAdapter(androidCharger); //Adapter Pattern
        System.out.println("Created an Apple Charger by converting an android charger");
        applePhone.plugAppleCharger(androidToAppleChargerAdapter);
        applePhone.charge();
    }
}Code language: Java (java)

Here, We have an ApplePhone object and AndroidCharger object. And we know for sure that these two implementations are not compatible. So We are using the adapter design pattern in Java to make things work. Here, The adapter is a type of AppleCharger. But under the hood, it’s an android charger. Here is the output that depicts the same.

Advantages

Adapter pattern has two major advantages of adapter pattern. They are,

  1. The adapter pattern is helpful when you have incompatible classes as we have seen before. Especially, There may be some classes that you might want to use but they are from a third-party library. So wrapping them inside an adapter might be a good idea.
  2. With this design pattern, you could reuse code without rewriting the whole component.

Disadvantages

There are couple of pitfalls you should be aware of while using this pattern.

  1. You would require as many adapters as the client needs. This may not be a problem for small applications. But make you are not using too many adapters.
  2. As the adapters act as an intermediate component, there may be performance overhead.

as always, you can find the code for this examples in our GitHub repository.

Exit mobile version