The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
The pattern is also called "Wrapper" because it is usually implemented using the technique of wrapping objects (object composition).
There are different situation when the pattern can be useful but a typical scenario is when you create an abstraction above code that is likely to change in the future. In this way, instead of changing the client code in the future the only thing to do will be implementing a particular adapter.
Let's see immediately an example.
Instead of defining an abstraction myself, I decided to base my example on the DbDataAdapter class available in the .NET Framework that defines an abstraction for data access operations.
Suppose we have a simple application that print the list of all the customers extracted from a local SQL server database.
This is an example of execution:
Suppose that a new vendor release a special file based database with the following code.
Assume the following new requirement:
- Use the new file database instead of SQL Server
It is obvious that the FileDb interface is completely different and incompatible with the interface expected by the client application.
What do you do?
You can use the Adapter Pattern!
In particular, you can create a specific DbDataAdapter class.
Of course you need to migrate the data from SQL Server to the file database:
The beauty of the pattern is that you don't need to change the client code. The only thing that you need to do is to simply use the new FileDbDataAdapter.
All the changes to implement the requirement are encapsulated in a single class: FileDbDataAdapter.
The designer of the application created the adapter abstraction since the beginning because he was aware that changes of the data access code are highly likely in the future. If this abstraction was not created the change would have been more intrusive that this.
Most of the applications using third party libraries use adapters as a middle layer between the application and the library itself to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code.
The main Object Oriented Principles used by the Adapter Pattern are the following:
- Favor composition over inheritance
- Encapsulate what varies
- Program to interfaces, not implementation
- Open/Closed principle