Learn the Adapter Design Pattern
This is the 7th post in a series on design patterns.
The adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.
You may be surprised when you try to charge your laptop for the first time when you travel from India to the US. There are different plug and socket standards in different countries. You can’t use your Indian plug in an America socket because of that. By using a power plug adapter that has an Indian-style socket and an American-style plug, the problem can be resolved.
Using a software development analogy, imagine you’re developing an application that works with the XML format only, but now it has to communicate with multiple APIs from 3rd parties that accept different formats. For example, some 3rd party APIs require XML, while others require JSON.
This problem can be solved by creating an adapter. This is a special object that converts the interface of one object so that another object can understand it.
Adapter Design Pattern
Adapters wrap one of the objects to hide the complexities of conversion. The wrapped object is unaware of the adapter.
As well as converting data into different formats, an adapter can also assist objects with different interfaces in collaborating. In order to solve the incompatibility, you can create XML-to-JSON converters. The adapter translates the incoming XML data into a JSON structure and passes it on to the appropriate 3rd party API.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
- At least two classes should have incompatible interfaces.
- Define the client adapter interface and describe how clients communicate with the service.
- Create an adapter class that follows the client interface.
- Add a field to the adapter class for storing a reference to the service object.
- In the adapter class, implement each method of the client adapter interface one by one. Adapters should delegate most of the real work to service objects, handling only interface or data format conversions.
Source Code Implementation
Imagine you have two classes that are incompatible with each other, AmericanSocket and IndianPlug. The Socket interface describes a protocol that other classes need to follow in order to work with the client code.
AdapterSocket works with both AmericanSocket and IndianPlug. It wraps the AmericanSocket interface while implementing the Socket interface. AdapterSocket receives calls from the client IndianPlug via the adapter interface and transforms them into calls to the wrapped AmericanSocket object in a format it understands.
AmericanSocket’s charge method cannot be used directly by IndianPlug due to its incompatible interface.
So long as IndianPlug works with the adapter via the interface, the client code does not get coupled to the concrete adapter class.
When To Apply Adapter Design Pattern
- When you want to use a class, but its interface is incompatible with the rest of your code, use the Adapter design pattern.
- When you want to reuse several existing subclasses that lack some common functionality and cannot be added to the superclass, use the adapter design pattern. This is very similar to the decorator design pattern.
Pros of Adapter Design Pattern
- With the Single Responsibility Principle, you can separate the interface or data conversion code from the main business logic.
- The Open/Closed Principle allows you to introduce new types of adapters into an application without breaking existing client code as long as the adapters can be accessed through the client interface.