Adapter Design Pattern

The word Adapt means suitable for a new use.

Rikam Palkar
Level Up Coding
Published in
4 min readMar 1, 2022

--

Photo by Maarten Wijnants on Unsplash

Let’s take an example from our homes, we all have seen electric sockets mounted on our walls. There is a strange fact about these sockets that every country has its own style of electric outlets. That’s why smartphone manufacturers make a different style of charging adapters that are specific to the country.

Another great example would be Apple’s Hyperdrive. It connects so many devices to a single USB port. Here, hyperdrive is acting as an Adapter.

Image source: HyperDrive Thunderbolt 3 Hub

The adapter also is known as a wrapper. cause it wraps objects that can be used by different objects.

Let’s see UML first.

  1. The client is basically the class who wants to use the pattern. The calling class.
  2. The client wants to have Specific_request() which can only be served by class Adaptee, we can directly have a HAS-A relationship and be done with it. But the problem lies when there is another specific_request which is served by let’s say another class Adaptee2, in this case, we have to make another HAS-A relationship and this could reoccur with every new requirement. So you see the problem, every time new request comes we have to map that to client class, now you’d argue what’s wrong with that approach well if you do that for every single request your code won’t be extensible as per “Open-Closed principle” we are Closed for Modification.

So how do we get past this before getting into too much of a mess!!

To deal with this chaos, we can abstract a concept of a new request and let abstraction handle delegation of a request made by the client. In the above UML, it is handled by the interface ITarget .

Let’s jump into coding.

Example, Let’s say our application reads data from an XML file and it serves the purpose for today but if tomorrow, we would like our application to support JSON, then what? That’s when we can use Adapter design pattern.

Let’s design the architecture for this problem. In the below diagram, we have 2 classes XMLAdapteeand JSONAdaptee, these classes are going to inherit the interface IEmployeeDetails which has an abstract method GetData(), so our classes can use their own implementation for their own logic.

The class program can inject XMLAdaptee’s instance to the Adapter object if it wants result in XML or it can pass JSONAdaptee’s instance if it wants result in JSON.

Now if tomorrow another requirement comes for YAML then we can simply create class YAMLAdaptee and write it’s own logic in GetData() method.

This is how our UML would look:

Let’s create an interface ITargetwhich will be called by our client.

Next, class Adapter,

which will implement ITarget: this class also has interface IEmployeeDetails : this interface will be implemented by both of our XML & JSON Adaptees to keep similar architecture in both of the classes, so our client code won’t change.

Let’s create an interface IEmployeeDetails:

An class employee and entity:

An class XMLAdaptee to load xml data. For now, we can generate data from code itself.

Next, class JSONAdaptee:

Last but not least, our caller class program:

Output for XML data: line number 15 in program.cs

Output for JSON data, just uncomment the above line in the code. line number 18 in program.cs

Perfect! I sincerely hope you enjoyed this article and that you’re inspired to apply what you’ve learned to your own applications. Thank you.

Happy coding!!

Catch me on Linkedin

--

--