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

  1. Identify objects or components that have interfaces that are not compatible with the interface the client expect.
  2. Create the desired interface (target) that the client expects, the interface defines the methods that the adapter should implement.
  3. 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);
    }
}
 

Design_PatternStructural_Design_PatternsSOFT2201Adapter_Pattern