Table of Contents
Introduction to Adapter Design Pattern
The Adapter Design Pattern is a structural design pattern that allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, converting the interface of one class into another interface that clients expect. This pattern is useful when integrating existing classes or systems that have incompatible interfaces.
Related Article: How to Find the Max Value of an Integer in Java
Purpose of Adapter Design Pattern
The purpose of the Adapter Design Pattern is to enable communication and collaboration between classes or systems with incompatible interfaces. It allows these classes to work together by providing a common interface that both sides can understand. This pattern helps to achieve interoperability and reusability by allowing classes to interact without making significant changes to their existing code.
Structural Elements of Adapter Design Pattern
The Adapter Design Pattern consists of the following structural elements:
1. Target: This is the interface that the client code expects to interact with.
2. Adaptee: This is the existing class or system with an incompatible interface.
3. Adapter: This is the class that implements the Target interface and wraps the Adaptee. It translates the requests from the client into calls to the Adaptee.
Roles of Adapter Design Pattern Components
The components of the Adapter Design Pattern play the following roles:
1. Target: Defines the interface that the client code interacts with.
2. Adaptee: Represents the existing class or system that needs to be adapted.
3. Adapter: Implements the Target interface and adapts the Adaptee's interface to match the Target interface.
Related Article: Java String Substring Tutorial
Operation of Adapter Design Pattern
The Adapter Design Pattern operates by receiving a request from the client code through the Target interface. The Adapter then translates this request into appropriate calls to the Adaptee's interface. The Adaptee performs the required actions and returns the result back to the Adapter, which then returns it to the client code through the Target interface.
Adapter Design Pattern: Use Case 1
One common use case of the Adapter Design Pattern is when integrating a third-party library or service into an existing system. Suppose we have an application that interacts with a legacy payment gateway that uses a different interface than the modern payment gateway we want to integrate. We can create an adapter that translates the requests and responses between the two interfaces, allowing the application to seamlessly work with both payment gateways.
Here's an example of how the Adapter Design Pattern can be used in Java:
// Target interfacepublic interface PaymentGateway { void processPayment(double amount);}// Adaptee classpublic class LegacyPaymentGateway { public void makePayment(double amount) { // Legacy payment gateway logic }}// Adapter classpublic class PaymentGatewayAdapter implements PaymentGateway { private LegacyPaymentGateway legacyPaymentGateway; public PaymentGatewayAdapter(LegacyPaymentGateway legacyPaymentGateway) { this.legacyPaymentGateway = legacyPaymentGateway; } @Override public void processPayment(double amount) { legacyPaymentGateway.makePayment(amount); }}// Client codepublic class Application { public static void main(String[] args) { // Using the modern payment gateway PaymentGateway modernPaymentGateway = new ModernPaymentGateway(); modernPaymentGateway.processPayment(100.0); // Using the legacy payment gateway through the adapter LegacyPaymentGateway legacyPaymentGateway = new LegacyPaymentGateway(); PaymentGatewayAdapter adapter = new PaymentGatewayAdapter(legacyPaymentGateway); adapter.processPayment(100.0); }}
In the above example, the PaymentGateway
interface represents the common interface expected by the client code. The LegacyPaymentGateway
class is the existing class with an incompatible interface. The PaymentGatewayAdapter
class implements the PaymentGateway
interface and adapts the LegacyPaymentGateway
interface to match the PaymentGateway
interface. The client code can use either the modern payment gateway directly or the legacy payment gateway through the adapter, without any changes to its code.
Adapter Design Pattern: Use Case 2
Another use case of the Adapter Design Pattern is when working with different data formats or protocols. For example, suppose we have an application that needs to process data from a CSV file and a JSON file. Instead of writing separate code to handle each file format, we can create adapters that translate the file-specific operations into a common interface that the application can work with.
Here's an example of how the Adapter Design Pattern can be used in Java for handling different file formats:
// Target interfacepublic interface FileReader { void readFile(String filePath);}// Adaptee classespublic class CsvFileReader { public void readCsvFile(String filePath) { // Read and process CSV file logic }}public class JsonFileReader { public void readJsonFile(String filePath) { // Read and process JSON file logic }}// Adapter classespublic class CsvFileReaderAdapter implements FileReader { private CsvFileReader csvFileReader; public CsvFileReaderAdapter(CsvFileReader csvFileReader) { this.csvFileReader = csvFileReader; } @Override public void readFile(String filePath) { csvFileReader.readCsvFile(filePath); }}public class JsonFileReaderAdapter implements FileReader { private JsonFileReader jsonFileReader; public JsonFileReaderAdapter(JsonFileReader jsonFileReader) { this.jsonFileReader = jsonFileReader; } @Override public void readFile(String filePath) { jsonFileReader.readJsonFile(filePath); }}// Client codepublic class Application { public static void main(String[] args) { FileReader csvFileReader = new CsvFileReaderAdapter(new CsvFileReader()); FileReader jsonFileReader = new JsonFileReaderAdapter(new JsonFileReader()); csvFileReader.readFile("data.csv"); jsonFileReader.readFile("data.json"); }}
In the above example, the FileReader
interface represents the common interface for reading files. The CsvFileReader
and JsonFileReader
classes are the existing classes with incompatible interfaces for reading CSV and JSON files, respectively. The CsvFileReaderAdapter
and JsonFileReaderAdapter
classes implement the FileReader
interface and adapt the respective file-specific interfaces to match the FileReader
interface. The client code can use the adapters to read CSV and JSON files using the common FileReader
interface.