If you have ever travelled to United States from countries like England or India, you face a very common problem. Sockets. In US of A, electric sockets are rectangular in shape where in India or England, it cylindrical in shape and so are the plugs being put into them. So how to connect? Easy, we carry an adapter, which allows us to work with two incompatible things , and that is our topic of today that is adapter pattern.
Adapter pattern is structural design pattern and works as a bridge between two incompatible interfaces. Intent of adapter pattern is to convert a class or interface into one which is required by client. This lets classes which are independent or incompatible to work together. There are four parts into adapter pattern: Target : this is the interface which is used by client, Adapter : Adapts the interface which needs to be used by client but not compatible, Adaptee : the incompatible interface, Client : Our beloved client.
There are two ways to implement adapter pattern:
Class Adapter: uses java inheritance to extend source interface
In this method, the class which needs to be used by client and has incompatible methods is extended and a child class is created. This new class which is created contains compatible methods. These compatible methods will eventually call incompatible methods of base class. This method can be implemented in languages which support multiple inheritance (Java, C# don’t support multiple inheritance and hence this cannot be used in these languages). This is because adapter needs to inherit both target and adaptee. However, if we make target as interface, then this problem goes away as class can implement as many interface as possible.
To illustrate, we will take example which we discussed above, the rectangular socket (returning 120V) and cylindrical plug (may take only 40V, 12V, 3V). First let’s create a class to represent rectangular socket returning 120V:
RectangularSocket class returning 120V volts
Now, we have cylindrical plug and which needs to get power from socket. However, the socket available takes on rectangular plug. What we will do is to inherit rectangular socket class and create an adapter class which will also take cylindrical plug too which can take 3V, 40V or 120V.
Cool now we have a client (cylindrical plug), Adaptee (rectangular socket) and adapter (class derived from rectangular socket). We have to make target interface which will be implemented by adapter and will be used by client, lets call it as IRectangularSocketAdapter.
Client using above interface:
Object Method: It uses java composition and adapter contains object of Adaptee class.
This is very simple way to implement adapter pattern, just add base class as an attribute to adapter class and use that attribute to call incompatible methods. This method has its own advantages: first, it adapts the base class and all inherited class of that base class which is not case in class base method. This comes with a caveat that if subclasses add new methods, adapter needs to change in order to expose those methods to clients.
Everything from above example of socket and plug still remains, only change is in adapter class which now contains Adaptee class (rectangular socket) as an attribute. Code below shows how adapter pattern using object method is used.
There are some pertinent questions : What amount of work should be done in adapter. That is simple to answer, the amount you require to make communication between two incompatible classes. If target and adaptee are more or less compatible, then adapter just needs to delegate calls to adaptee. If target and adaptee are incompatible, we may have to do a good heavy lifting, like data structure conversions etc.
Other question, when should we use adapter pattern? Again simple question, most of the times we face it. When you want to use a class which cannot be changed and you already have implemented logic to use that class, but taking some assumptions which are not correct or you are replacing the class which was supporting your earlier implementation and replacing with new class which cannot be changed. This case is best suited for adaption. You write an adapter which provides a way to use new class using your existing code.
Today, we learned something about a method which is heavily used to use legacy codes and this is called as adapter pattern.Please leave comments/suggestions if you like explanation or if there is something which can be improved or corrected.