The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to collaborate together. This pattern acts as a bridge between two classes, allowing them to work together without changing their source code. The existing examples in Java core libraries are:
Applicability
- When the client is expecting some type of objects and you have an object (adaptee) offering the same features but exposing a different interface.
- When you have multiple classes or components with varying interfaces, and you want them to confront a common interface to simplify the usage and maintenance.
- You have third parties libraries that cannot directly used by your application client because of incompatible interfaces.
Variations
Class adapter (inheritance based)
In a Class Adapter, the adapter class inherits from both the target interface and the adaptee class with multiple inheritance (supported in C++).
In Java this can be implement as the following:
class Adapter extends Adaptee implements Target {
@Override public void request() {
specificRequest(); // Call the adaptee's method
}
}
Object adapter (composition based)
The adapter class contains an instance of the adaptee class.
Approach
- Identify objects or components that have interfaces that are not compatible with the interface the client expect.
- Create the desired interface (target) that the client expects, the interface defines the methods that the adapter should implement.
- Create adapter class that implement the interface, inside the methods, they delegates the calls to the corresponding methods of the adaptees, translate or adapting the parameters as necessary.
Components
- Target interface
- An interface that the client required, defines the methods that the client needs.
- Adaptee
- The class or component with incompatible interface that you want to adapt to the target interface.
- The adaptee contains the methods you want to reuse but does not confront the target interface.
- Adapter
- The adapter bridges the gap between the target interface and the adaptee interface.
- The adapter class implements the target interface.
- The adapter class contains a instance of the adaptee class.
- The adapter class delegates the call to the the adaptee instance, translate and adapting data as necessary.
Example 1: Class adapter
Identify adapter pattern components
Target interface: Shape
Adaptee: XXCircle
Adapter: Circle
In this example, for instance, the client wants to draw the XXCircle
through the Shape
interface and its display
method. However, the XXCircle
is not compatible with the Shape
interface and it has its own methods of displayit
to perform the draw operation.
The client wants to draw the
XXCircle
through the Shape
interface with display()
method. We introduce an adapter Circle
that implement the client desired interface Shape
, meanwhile the Circle
class delegate the draw call to XXCircle
‘s displayit()
.
Example 2: Object adapter
Identify Adapter pattern components
Target interface: JSONDataProcessor
Adaptee: CSVDataFormatter
Adapter: CSVToJSONAdapter
Adaptee
This CSVDataFormatter
has method the client wants to use but does not confront the desired interface (The client want JSON format).
// class with an incompatible CSV format
class CSVDataFormatter {
// the formatCSVData is not what the client wants
public String formatCSVData(String data) {
return "CSV: " + data;
}
}
Target interface
The JSONDataProcessor
defines a processJSONData
method which is what client wants to use.
// system expects data in JSON format
class JSONDataProcessor {
// the processJSONData method is what client wants to use
public String processJSONData(String jsonData) {
return "Processed JSON: " + jsonData;
}
}
Adapter
The adapter class is the bridge between the target interface and the adaptee. It implements the target interface and internally delegates calls to the adaptee.
// Adapter to make the CSVDataFormatter compatible with the JSONDataProcessor
class CSVToJSONAdapter extends JSONDataProcessor {
private CSVDataFormatter csvFormatter;
public CSVToJSONAdapter(CSVDataFormatter csvFormatter) {
this.csvFormatter = csvFormatter;
}
public String processCSVData(String csvData) {
// Adapt the CSV data to JSON format using the CSVDataFormatter
String jsonData = csvFormatter.formatCSVData(csvData);
// Delegate the processing to the JSONDataProcessor
return super.processJSONData(jsonData);
}
}
Client
public class Client {
public static void main(String[] args) {
// the adaptee
CSVDataFormatter csvFormatter = new CSVDataFormatter();
// adapter to make it compatible with JSONDataProcessor
CSVToJSONAdapter adapter = new CSVToJSONAdapter(csvFormatter);
// client can now process CSV data using the adapter
String csvData = "Sample CSV data";
// now the processed data is in JSON format
String processedData = adapter.processCSVData(csvData);
}
}
Back to parent page: Structural Patterns
Design_Pattern Structural_Design_Patterns SOFT2201 Adapter_Pattern