Adapter Pattern
An Adapter Pattern says that just “converts the interface of a class into another interface that a client wants”.
In other words, to provide the interface according to client requirement while using the services of a class with a different interface.
Adapter design pattern is one of the structural design pattern and its used so that two unrelated interfaces can work together. The object that joins these unrelated interface is called an Adapter.
The Adapter Pattern is also known as Wrapper.
Advantage of Adapter Pattern
- It allows two or more previously incompatible objects to interact.
- It allows reusability of existing functionality.
Usage of Adapter pattern:
It is used:
- When an object needs to utilize an existing class with an incompatible interface.
- When you want to create a reusable class that cooperates with classes which don’t have compatible interfaces.
- When you want to create a reusable class that cooperates with classes which don’t have compatible interfaces.
Example of Adapter Pattern
Let’s understand the example of adapter design pattern by the above UML diagram.
UML for Adapter Pattern:
There are the following specifications for the adapter pattern:
- Target Interface: This is the desired interface class which will be used by the clients.
- Adapter class: This class is a wrapper class which implements the desired target interface and modifies the specific request available from the Adaptee class.
- Adaptee class: This is the class which is used by the Adapter class to reuse the existing functionality and modify them for desired use.
- Client: This class will interact with the Adapter class.
Implementation of above UML:
Step 1
Create a CreditCard interface (Target interface).
public interface CreditCard {
public void giveBankDetails();
public String getCreditCard();
}// End of the CreditCard interface.
Step 2
Create a BankDetails class (Adaptee class).
// This is the adapter class.
public class BankDetails {
private String bankName;
private String accHolderName;
private long accNumber;
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public String getAccHolderName() {
return accHolderName;
}
public void setAccHolderName(String accHolderName) {
this.accHolderName = accHolderName;
}
public long getAccNumber() {
return accNumber;
}
public void setAccNumber(long accNumber) {
this.accNumber = accNumber;
}
}// End of the BankDetails class.
Step 3
Create a BankCustomer class (Adapter class).
// This is the adapter class
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class BankCustomer extends BankDetails implements CreditCard {
public void giveBankDetails() {
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print(“Enter the account holder name :”);
String customername = br.readLine();
System.out.print(“\n”);
System.out.print(“Enter the account number:”);
long accno = Long.parseLong(br.readLine());
System.out.print(“\n”);
System.out.print(“Enter the bank name :”);
String bankname = br.readLine();
setAccHolderName(customername);
setAccNumber(accno);
setBankName(bankname);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String getCreditCard() {
long accno=getAccNumber();
String accholdername=getAccHolderName();
String bname=getBankName();
return (“The Account number “+accno+” of “+accholdername+” in “+bname+ ”
bank is valid and authenticated for issuing the credit card. “);
}
}// End of the BankCustomer class.
Step 4
Create a AdapterPatternDemo class (client class).
//This is the client class.
public class AdapterPatternDemo {
public static void main(String args[]) {
CreditCard targetInterface = new BankCustomer();
targetInterface.giveBankDetails();
System.out.print(targetInterface.getCreditCard());
}
}// End of the BankCustomer class.
Output:
Enter the account holder name :Deepak Bhardwaj
Enter the account number:10001
Enter the bank name :SBI
The Account number 10001 of Deepak Bhardwaj in SBI bank is valid
and authenticated for issuing the credit card.
Example 2.
One of the great real life example of Adapter design pattern is mobile charger. 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.
We will try to implement multi-adapter using adapter design pattern in this tutorial.
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); }
}
public interface SocketAdapter {
public Volt get120Volt();
public Volt get12Volt(); public Volt get3Volt();
}
Two Way Adapter Pattern
While implementing Adapter pattern, there are two approaches – class adapter and object adapter – however both these approaches produce same result.
- Class Adapter – This form uses java inheritance and extends the source interface, in our case Socket class.
- Object Adapter – This form uses Java Composition and adapter contains the source object.
Adapter Design Pattern – Class Adapter
Here is the class adapter approach implementation of our adapter.
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);
}
}
Adapter Design Pattern – Object Adapter Implementation
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);
}
}
Notice that both the adapter implementations are almost same and they implement the SocketAdapter
interface. The adapter interface can also be an abstract class.
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();
}
When we run above test program, we get following output.
v3 volts using Class Adapter=3 v12 volts using Class Adapter=12 v120 volts using Class Adapter=120 v3 volts using Object Adapter=3 v12 volts using Object Adapter=12 v120 volts using Object Adapter=120
Adapter Design Pattern Example in JDK
Some of the adapter design pattern example I could easily find in JDK classes are;
- java.util.Arrays#asList()
- java.io.InputStreamReader(InputStream) (returns a Reader)
- java.io.OutputStreamWriter(OutputStream) (returns a Writer)