Structural Design Patterns provide different ways to create a class structure, for example using inheritance and composition to create a large object from small objects. Following design patterns come under this category.
Adapter pattern lets you wrap an otherwise incompatible object in an adapter to make it compatible with another class.
Adapter pattern works as a bridge between two incompatible interfaces. Sometimes, there could be a scenario when two objects don’t fit together, as they should in-order to get the work done. This situation could arise when we are trying to integrate a legacy code with a new code, or when changing a 3rd party API in the code. This is due to incompatible interfaces of the two objects which do not fit together. In this case we can use Adapter design pattern.
As a real life example, we can think of a mobile charger as an adapter because mobile battery needs 3 volts to charge but the normal socket produces either 120V (US) or 240V (India). So the mobile charger works as an adapter between mobile charging socket and the wall socket.
Adapter design pattern is used so that two unrelated interfaces can work together. The object that joins these unrelated interfaces is called an Adapter. In the adapter pattern, a wrapper class (i.e., the adapter) is used translate requests from it to another class (i.e., the adoptee). In effect, an adapter provides particular interactions with an adoptee that are not offered directly by the adoptee.
UML diagram of generic adapter design pattern:
Elements:
The Adapter pattern should be used when:
Let's take a look at the interactions in a sequence diagram.
Java
So first of all we will have two classes – Volt
(to measure volts) and Socket
(producing constant volts of 120V).
public class Volt { private int volts; public Volt(int v) { this.volts=v; } public int getVolts() { return volts; } public void setVolts(int volts) { this.volts = volts; } }
public class Socket { public Volt getVolt(){ return new Volt(120); } }
Now we want to build an adapter that can produce 3 volts, 12 volts and default 120 volts. So first of all we will create an adapter interface with these methods.
public interface SocketAdapter { public Volt get120Volt(); public Volt get12Volt(); public Volt get3Volt(); }
While implementing Adapter pattern, there are two approaches – class adapter and object adapter – however both these approaches produce same result.
Socket
class.Here is the class adapter approach implementation of our adapter.
// using inheritance for adapter pattern public class SocketClassAdapterImpl extends Socket implements SocketAdapter { @Override public Volt get120Volt() { return getVolt(); } @Override public Volt get12Volt() { Volt v = getVolt(); return convertVolt(v,10); } @Override public Volt get3Volt() { Volt v = getVolt(); return convertVolt(v,40); } private Volt convertVolt(Volt v, int i) { return new Volt(v.getVolts()/i); } }
Here is the object adapter implementation of our adapter.
public class SocketObjectAdapterImpl implements SocketAdapter { // using composition for adapter pattern private Socket sock = new Socket(); @Override public Volt get120Volt() { return sock.getVolt(); } @Override public Volt get12Volt() { Volt v = sock.getVolt(); return convertVolt(v,10); } @Override public Volt get3Volt() { Volt v = sock.getVolt(); return convertVolt(v,40); } private Volt convertVolt(Volt v, int i) { return new Volt(v.getVolts()/i); } }
Here is a test program to consume our adapter design pattern implementation.
public class AdapterPatternTest { public static void main(String[] args) { testClassAdapter(); testObjectAdapter(); } private static void testObjectAdapter() { SocketAdapter sockAdapter = new SocketObjectAdapterImpl(); Volt v3 = getVolt(sockAdapter,3); Volt v12 = getVolt(sockAdapter,12); Volt v120 = getVolt(sockAdapter,120); System.out.println("v3 volts using Object Adapter="+v3.getVolts()); System.out.println("v12 volts using Object Adapter="+v12.getVolts()); System.out.println("v120 volts using Object Adapter="+v120.getVolts()); } private static void testClassAdapter() { SocketAdapter sockAdapter = new SocketClassAdapterImpl(); Volt v3 = getVolt(sockAdapter,3); Volt v12 = getVolt(sockAdapter,12); Volt v120 = getVolt(sockAdapter,120); System.out.println("v3 volts using Class Adapter="+v3.getVolts()); System.out.println("v12 volts using Class Adapter="+v12.getVolts()); System.out.println("v120 volts using Class Adapter="+v120.getVolts()); } private static Volt getVolt(SocketAdapter sockAdapter, int i) { switch (i){ case 3: return sockAdapter.get3Volt(); case 12: return sockAdapter.get12Volt(); case 120: return sockAdapter.get120Volt(); default: return sockAdapter.get120Volt(); } } }
Python
class Volt: def __init__(self, volt): self.volt = volt def get_volt(self): return self.volt def set_volt(self): self.volt = volt class Socket: def get_volt(self): return Volt(120) class SocketClassAdapterImpl(Socket): def get_120volt(self): return self.get_volt() def get_12volt(self): v = self.get_volt() return self.convert_volt(v, 10) def get_3volt(self): v = self.get_volt() return self.convert_volt(v, 40) def convert_volt(self, v, i): return Volt(v.get_volt() / i) def get_volt(sock_adapter, i): if i == 3: return sock_adapter.get_3volt() elif i == 12: return sock_adapter.get_12volt() elif i == 120: return sock_adapter.get_120volt() return sock_adapter.get_120volt() if __name__ == '__main__': sock_adapter = SocketClassAdapterImpl() v3 = get_volt(sock_adapter, 3) v12 = get_volt(sock_adapter, 12) v120 = get_volt(sock_adapter, 120) print("v3 volts using Class Adapter=" + str(v3.get_volt())) print("v12 volts using Class Adapter=" + str(v12.get_volt())) print("v120 volts using Class Adapter=" + str(v120.get_volt()))