Adapter pattern is used when an interface does not match the new requirement and the existing interface needs to adapt to another interface.
NOTES
In this article, we discuss the implementation of the Adapter Pattern in Java.
See the Adapter in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Adapter Pattern-
Examples
Here are a few examples of the Adapter pattern in Java.
Example #1: API with File Adapter [Object Adapter]
Let’s consider a system that is used for calling API. The system can call native APIs and 3rd party APIs.
There is another part of the system that can perform operation on files.
Now, for some specific operations, if we want the file operations to behave as an API and be a part of the API system, then we need an adapter. Let’s see how can we implement the adapter.
File Interface
This is the interface that the file operation class implements. This file is preexisting before the adapter implementation.
// File.java
package com.bigboxcode.designpattern.adapter.api;
public interface File {
String readFile();
void writeFile(String input);
}
FileOp Class [implements File Interface]
Class that performs different file operations. This file is preexisting before the adapter implementation.
// FileOp.java
package com.bigboxcode.designpattern.adapter.api;
public class FileOp implements File{
public String readFile() {
// Code to read from file
System.out.println("Reading from file");
return "some dummy response read from file";
}
public void writeFile(String input) {
// Write to file related code here
System.out.println("Writing to file: " + input);
}
}
API Interface
Interface for all API classes. This file is preexisting before the adapter implementation.
package com.bigboxcode.designpattern.adapter.api;
public interface Api {
String fetchData();
void sendData(String data);
}
Native API Class [implements Api interface]
Native API class (dummy) as an implement of the API interface, so this can be used as an API without any change.
This file is preexisting before the adapter implementation.
// NativeApi.java
package com.bigboxcode.designpattern.adapter.api;
public class NativeApi implements Api {
@Override
public String fetchData() {
// code to fetch data from native API
System.out.println("Fetching data from Native API");
return "Data read from Native Api";
}
@Override
public void sendData(String data) {
// code to send data to native API
System.out.println("Sending data to Native API: " + data);
}
}
Third-Party API Class [implements Api interface]
3rd party API class (dummy) as an implement of the API interface, so this can be used as an API without any change.
This file is preexisting before the adapter implementation.
// ThirdPartApi.java
package com.bigboxcode.designpattern.adapter.api;
public class ThirdPartyApi implements Api {
@Override
public String fetchData() {
// code to fetch data from Third Party API
System.out.println("Fetching data from Third Party API");
return "Data read from Third Party Api";
}
@Override
public void sendData(String data) {
// code to send data to Third Party API
System.out.println("Sending data to Third Party API: " + data);
}
}
New Requirement
For some API operations, we need to get data from files and also write data to files. Though these are file operations, but these operations need to be done as API operations.
The file operation class needs to adapt to the functionality of API. To achieve that we need an adapter that works as a bridge and enable API to perform file operations using file-related classes.
File Adapter
File adapter that we need to create, for implementing the new adapter required. Here are a few key things to notice here.
- Adapter class implements the interface to which we need to adapt (API interface).
- There is a variable that holds a File object.
- The constructor accepts a File object as a parameter and saves that to the class variable.
- For the operations, the adapter uses methods from the file object.
// FileAdapter.java
package com.bigboxcode.designpattern.adapter.api;
public class FileAdapter implements Api {
private final File file;
public FileAdapter(File file) {
this.file = file;
}
@Override
public String fetchData() {
// May perform additional operation or processing
// before or after data is fetched
return file.readFile();
}
@Override
public void sendData(String data) {
// May perform additional operation or processing
// before or after data is written to file
file.writeFile(data);
}
}
Demo
// Demo.java
package com.bigboxcode.designpattern.adapter.api;
public class Demo {
public static void main(String[] args) {
// make a call to third part API for testing
Api thirdPartyApi = new ThirdPartyApi();
thirdPartyApi.fetchData();
thirdPartyApi.sendData("1234");
// Make a call to the file via FileAdapter
File file = new FileOp();
FileAdapter fileAdapter = new FileAdapter(file);
fileAdapter.fetchData();
fileAdapter.sendData("ABCDEF");
}
}
Output
Fetching data from Third Party API
Sending data to Third Party API: 1234
Reading from file
Writing to file: ABCDEF
Example #2: Transport [Object Adpater]
Existing Situation
In the existing code, we already have classes named Plane and Helicopter. Both these classes implement an interface named AirTransport.
New requirement
Then sometime later we are trying to add a feature for a transport system. So we have created an interface named Transport and all the transport-related classes will implement the Transport interface.
Problem
The AirTransport interface and its implementations do not match the new Transport interface. And we don’t want to change the existing interface(AirTransport) and its implementations (Plane and Helicopter)
Solution
- Create a new class named AirTransportAdapter.
- Import Transport interface in AirTransportAdapter.
- Implement all required functions, and make any required changes to achieve the final result.
- While using the new adapter class, pass the object in the constructor.
Class Diagram
Take a look at the class diagram.
AirTransport Interface
// AirTransport.java
package com.bigboxcode.designpattern.adapter.transport;
public interface AirTransport {
int getNumberOfWheels();
int getNumberOfEngines();
double getWeight();
// In Nautical miles
double getDistanceTravelled();
double getTravelCostTotal();
}
Plane Class [implements AirTransport]
// Plane.java
package com.bigboxcode.designpattern.adapter.transport;
public class Plane implements AirTransport {
@Override
public int getNumberOfWheels() {
return 3;
}
@Override
public int getNumberOfEngines() {
return 2;
}
// get weight in pound
@Override
public double getWeight() {
return 127_000;
}
// In Nautical miles
@Override
public double getDistanceTravelled() {
return 500; // Nautical files
}
@Override
public double getTravelCostTotal() {
return 3_000;
}
}
Helicopter Class [implements AirTransport]
// Helicopter.java
package com.bigboxcode.designpattern.adapter.transport;
public class Helicopter implements AirTransport {
@Override
public int getNumberOfWheels() {
return 0;
}
@Override
public int getNumberOfEngines() {
return 1;
}
// Get weight in LB
@Override
public double getWeight() {
return 12_000;
}
// In Nautical miles
@Override
public double getDistanceTravelled() {
return 180; // nautical miles
}
@Override
public double getTravelCostTotal() {
return 20_000;
}
}
Transport Interface
// Transport.java
package com.bigboxcode.designpattern.adapter.transport;
public interface Transport {
int getNumberOfWheels();
double getWeight();
// In miles
double getDistanceTravelled();
double getTravelCostPerMile();
}
Bus Class [implements Transport]
// Bus.java
package com.bigboxcode.designpattern.adapter.transport;
public class Bus implements Transport {
@Override
public int getNumberOfWheels() {
return 4;
}
@Override
public double getWeight() {
return 10_000;
}
@Override
public double getDistanceTravelled() {
return 1_000;
}
@Override
public double getTravelCostPerMile() {
return 5;
}
}
Bike Class [implements Transport]
// Bike.java
package com.bigboxcode.designpattern.adapter.transport;
public class Bike implements Transport {
@Override
public int getNumberOfWheels() {
return 2;
}
@Override
public double getWeight() {
return 700;
}
@Override
public double getDistanceTravelled() {
return 80;
}
@Override
public double getTravelCostPerMile() {
return 4;
}
}
AirTransportAdapter Class [implements Transport]
// AirTransportAdapter.java
package com.bigboxcode.designpattern.adapter.transport;
public class AirTransportAdapter implements Transport {
private final AirTransport airTransport;
public AirTransportAdapter(AirTransport airTransport) {
this.airTransport = airTransport;
}
@Override
public int getNumberOfWheels() {
return this.airTransport.getNumberOfWheels();
}
@Override
public double getWeight() {
return this.airTransport.getWeight();
}
@Override
public double getDistanceTravelled() {
// Convert nautical mile to mile and return
double distanceInNauticalMile = this.airTransport.getDistanceTravelled();
return distanceInNauticalMile * 1.151;
}
@Override
public double getTravelCostPerMile() {
// calculate cost per mile from total cost
double totalCost = this.airTransport.getTravelCostTotal();
return totalCost / this.getDistanceTravelled();
}
}
Demo
// Demo.java
package com.bigboxcode.designpattern.adapter.transport;
public class Demo {
public static void main(String[] args) {
System.out.println("Get information of Bus travel...");
Bus bus = new Bus();
System.out.println("nNumber of wheels: " + bus.getNumberOfWheels());
System.out.println("Weight(kg): " + bus.getWeight());
System.out.println("Distance(miles): " + bus.getDistanceTravelled());
System.out.println("Cost per mile: " + bus.getTravelCostPerMile());
System.out.println("nn-------------------------------------------nn");
System.out.println("Get information of Plane travel...");
AirTransportAdapter planeTransport = new AirTransportAdapter(new Plane());
System.out.println("nNumber of wheels: " + planeTransport.getNumberOfWheels());
System.out.println("Weight(kg): " + planeTransport.getWeight());
System.out.println("Distance(miles): " + planeTransport.getDistanceTravelled());
System.out.println("Cost per mile: " + planeTransport.getTravelCostPerMile());
}
}
Output
Get information of Bus travel...
Number of wheels: 4
Weight(kg): 10000.0
Distance(miles): 1000.0
Cost per mile: 5.0
-------------------------------------------
Get information of Plane travel...
Number of wheels: 3
Weight(kg): 127000.0
Distance(miles): 575.5
Cost per mile: 5.212858384013901
Source Code
Use the following link to get the source code:
Other Code Implementations
Use the following links to check Adapter pattern implementation in other programming languages.