Name: Adapter
Type: Structural
“Convert the interface of a class into another interface the client expects. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”
In other words, this pattern makes incompatible interfaces compatible.
Sometimes, objects just don’t fit together as they should. Either the object is too complex to work with or their interfaces are incompatible. The adapter design pattern lets you adapt what an object or class has to offer, by converting the interface of a class into another one. There are some common use cases like: integrating external libraries with different interfaces, working with legacy systems or adapting data formats
One of the real-life encounters with an Adapter is with headphone jacks. These jacks aren’t universal, and we won’t find the same jacks in all phone models. In these cases we might need adapters to convert a 3.5mm jack to a USB-C or Lightning connector, allowing headphones to work with different devices.
In all of these cases, the adapter is a middleman that translates the signals or data from one system to another, making it possible to connect incompatible objects or interfaces.
Imagine two people who speak different languages trying to have a conversation. The Adapter acts like a helpful translator, listening to one person (object 1) in their language and then seamlessly converting their message into terms understandable by the other person (object 2). This allows them to communicate effectively despite their initial incompatibility.
For the Adapter design pattern, we have three main entities involved.
iPhone
needs to be charged with a different chargerLightningToTypeCAdapter
is the class that knows how to talk with both the client and the Adaptee(i.e knows how to adapt a Lightning port to type C one)You can see in the diagram below the interaction between classes.
public interface ITypeCPort
{
void Recharge();
void UseTypeC();
}
public interface ILightningPort
{
void Recharge();
void UseLightning();
}
Then we have an IPhone
that implements the ILightningPort
.
public class IOSPhone : ILightningPort
{
private bool isConnected = false;
public void UseLightning()
{
isConnected = true;
Console.WriteLine("Lightning connection established");
}
public void Recharge()
{
if (isConnected)
{
Console.WriteLine("Recharging iPhone...");
}
else
{
Console.WriteLine("Please connect Lightning first");
}
}
}
Then we need to have an adapter.
public class LightningToTypeCAdapter : ITypeCPort
{
private ILightningPort lightningPhone;
public LightningToTypeCAdapter(ILightningPort lightningPhone)
{
this.lightningPhone = lightningPhone;
}
public void UseTypeC()
{
Console.WriteLine("Adapter converts Type-C to Lightning");
lightningPhone.UseLightning();
}
public void Recharge()
{
lightningPhone.Recharge();
}
}
From the client's perspective, now we can have an iPhone, use an adapter and recharge our phone.
IOSPhone myIPhone = new IOSPhone();
LightningToTypeCAdapter typeCAdapter = new LightningToTypeCAdapter(myIPhone);
Console.WriteLine("Attempting to recharge iPhone with Type-C via adapter:");
typeCAdapter.UseTypeC();
typeCAdapter.Recharge();
Structurally speaking, the Adapter design pattern is very similar to the Proxy design pattern. But unlike Proxy, The Adapter pattern is visible to the client, and the client knows that it interacts with an adapter.
Hi! Welcome to my blog