Table of Contents
Introduction
The Adapter design pattern is a structural pattern that allows objects with incompatible interfaces to work together. It does this by converting the interface of one class into another interface that the client expects. This pattern is often used to make existing classes work with each other without modifying their source code.
Real-world example
Consider the mundane task of pouring water from a can into a bottle. You would have no problem if the can had a straw like this:
However, in case you have a big can and a small bottle, you probably not be able to complete the task:
In this case, what would you do? You would get a funnel to get the job done.
That is an example of the adapter pattern in real life. And yes, we are not using the wall socket example!
Code Examples
Imagine you have an iPhone (in 2022, all iPhones still use the lightning charger) and go to a party without bringing your phone charger. You ask around and no one has an iPhone charger. All people use type-c chargers.
You are now desperate because the battery is almost dead and you can’t live without your iPhone (you can’t live a single minute without scrolling social media sites up and down).
Luckily, someone comes and gives you an adapter. On one end, it has a female type-c port. On the other end, it has a male lightning plug.
Which is exactly like this:
You thank the gentleman for providing life support and use the adapter right away to start charging your iPhone.
Now let’s see how we can do the same thing with code. Let’s first consider the diagram of interfaces:
Here, you can see that we have two types of chargers: TypeCCharger and LightningCharger. They both implement the Charger interface which has only one abstract method: transferElectricity
.
The IPhone
class only accepts a LightningCharger
. Thus, the type-c charger would not work. However, we created an adapter class that implements the LightningCharger
interface. This guarantees the iPhone could use instances of this class.
In addition, the adapter class takes the TypeC charger as its constructor’s parameter, and in its transferElectricity
method, applied the logic to get the energy from the type-c charger to transfer to the iPhone.
Here is the code:
package com.datmt.java_core.dp; public class AdapterPattern { public static void main(String[] args) { var iphone = new IPhone(); var typeCCharger = new TypeCChargerImpl(); var adapter = new LightningTypeCChargerAdapter(typeCCharger); iphone.charge(adapter); } } interface Charger { void transferElectricity(); } interface LightningCharger extends Charger { } class LightningChargerImpl implements LightningCharger { @Override public void transferElectricity() { } } interface TypeCCharger extends Charger { } class TypeCChargerImpl implements TypeCCharger { @Override public void transferElectricity() { } } class LightningTypeCChargerAdapter implements LightningCharger { private TypeCCharger typeCCharger; public LightningTypeCChargerAdapter(TypeCCharger typeCCharger) { this.typeCCharger = typeCCharger; } @Override public void transferElectricity() { this.typeCCharger.transferElectricity(); } } class IPhone { void charge(LightningCharger charger) { //charge } }
Conclusion
The Adapter pattern enables classes with incompatible interfaces to interact with each other. It does this by introducing a new class, the Adapter class, to convert the foreign interface (type-c charger) into an interface similar (the lightning charger) to the requested class (iPhone).
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.