The adapter pattern is one of the most useful patterns in my eyes. Therefore I want to explain what the adapter is and present a simple real life example on how it can be used.
It works the same way as a real-life adapter, for example for a power outlet. If you travel from the European Union to Switzerland or the US your normal power plug won’t fit into the power outlet. Hence you have to get an adapter which can link the power outlet with the power plug. This example perfectly describes how the adapter pattern works.
The adapter pattern is often used in combination with third-party libraries. For example, your client needs to utilize a specific interface and a library which you have to use doesn’t use this Interface or the library expects a different Interface. This is where the adapter comes to use. The adapter sits between the client and the library and connects them together. Like in the real world an adapter helps two classes which are not compatible to work together.
On the other hand, if you develop the library, you can provide support for future adapters so your users can implement it easily into their application.
The UML diagram for the adapter pattern is pretty simple. The client wants to call an operation on the Adaptee. To do that the client implements the Adapter interface and calls the Operation method. The ConcreteAdapter implements the method and calls the AdaptedOperation of the adaptee. After the execution, the ConcreteAdapter returns the information needed to the client.
Let’s look at a real time example
As an example, I import a list of my employees and then use a third party tool to a fancy header and footer to the list while printing it. Let’s say that my internal SAP system returns my employees as string array. The third-party tool expects a list of strings though. Therefore I need an adapter which to enable me to use the library with my string array.
The third-party tool called FancyReportingTool is pretty simple too. It is instantiated with an interface which will provide the data for printing in the ShowEmployeeList method. The interface I provide during the instantiating of the FancyReportingTool is the Adapter interface, which is implemented by the concrete adapter.
The constructor of the library asks for an interface. Because of this interface, it is possible for me to use the adapter. Remember this when creating libraries yourself. It’s good practice to provide support for future adapters.
The last missing piece is the ConcreteAdapter which is called EmployeeAdapter. This class inherits from the interface and form the SAPSystem. The adapter gets the employees from the SAPSystem class and converts the array into a list and returns it. The FancyReportingTool can print this list now.
With everything set up, I can create an instance of the interface, an instance of the FancyReportingTool with this interface and then call the ShowEmplyeeList on the FancyReportingTool object. This will get the employee data from my internal SAPSystem, convert it and use the third party library to print the data to the console.
In addition to the employee adapter, I could implement another adapter. The additional adapter could work as a data provider for my inventory and then send it to the third-party library for a nice print out.
In my eyes there are three related patterns which are worth to take a look at when learning the adapter pattern.
The repository and strategy pattern often implement an adapter whereas the facade is pretty similar to the adapter pattern. The difference between facade and adapter is that the facade usually wraps many classes to simplify interfaces. On the contrary the adapter mostly only wraps a single class.
In this example, I showed how to use the adapter pattern to combine two incompatible classes. This pattern is often used in combination with third-party libraries which have to be used.
You can find the source code of the example on GitHub.