In the realm of design patterns, the Adapter pattern stands as one of the simplest and most intuitive in the structural category. This pattern excels in bridging the gap between different interfaces, making it easier for systems to communicate seamlessly. Let’s delve into the workings of the Adapter pattern and how it can be effectively implemented in Java.
Table of contents
Open Table of contents
Sections
What is the Adapter Pattern?
The Adapter pattern plays a crucial role in converting one interface of a class into another interface that a client expects. This is immensely useful when integrating legacy code or third-party libraries into a current project. Often, inconsistencies exist between the interfaces of these different systems, and the Adapter pattern comes to the rescue by harmonizing them.
Imagine a scenario where we have some legacy code with specific functionality we want to use in our current project. However, due to interface inconsistencies, direct use of this functionality is not feasible. This is where the Adapter pattern shines—it allows us to convert data or interfaces, ensuring smooth communication between systems.
To visualize this, consider a client working on a project with a specific target call. The client needs to access a specific call in some legacy code, but the correct interface for direct communication is missing. The Adapter pattern acts as a bridge, converting the client’s call to match the third-party system’s specific call, facilitating effective communication.
Implementing the Adapter Pattern
Let’s proceed to implement the Adapter pattern in Java using a simple example.
Step 1: Define Third-Party Data Type
First, we assume a third-party data type, let’s call it DisplayDataThirdParty, which cannot be modified. This data type has two parameters: index (float) and someData (string).
public class DisplayDataThirdParty {
public float index;
public String someData;
public DisplayDataThirdParty(float index, String someData) {
this.index = index;
this.someData = someData;
}
public void displayData() {
System.out.println("Data is displayed: " + index + " - " + someData);
}
}
Step 2: Define Current Data Type
Next, we define a current data type, DatabaseData, which is assumed to be part of our system. This data type also has two parameters: position (int) and amount (int).
public class DatabaseData {
public int position;
public int amount;
public DatabaseData(int position, int amount) {
this.position = position;
this.amount = amount;
}
}
For simplicity, we’ll create a DatabaseDataGenerator class to generate example data for DatabaseData.
Step 3: Create an Adapter Interface
Now, let’s create an adapter interface, DatabaseDataAdapter, that defines a method to convert DatabaseData to DisplayDataThirdParty.
public interface DatabaseDataAdapter {
List<DisplayDataThirdParty> convertData(List<DatabaseData> data);
}
Step 4: Implement the Adapter
We’ll then implement the adapter, DatabaseDataAdapterImpl, which converts DatabaseData to DisplayDataThirdParty.
public class DatabaseDataAdapterImpl implements DatabaseDataAdapter {
@Override
public List<DisplayDataThirdParty> convertData(List<DatabaseData> data) {
List<DisplayDataThirdParty> result = new ArrayList<>();
for (DatabaseData datum : data) {
DisplayDataThirdParty displayData = new DisplayDataThirdParty(datum.position, Integer.toString(datum.amount));
result.add(displayData);
}
return result;
}
}
Step 5: Utilize the Adapter
Finally, let’s create a client that uses the adapter to convert and display the data.
public class Client {
public static void main(String[] args) {
// Generate example database data
DatabaseDataGenerator generator = new DatabaseDataGenerator();
List<DatabaseData> databaseData = generator.generateData();
// Create the adapter and convert data
DatabaseDataAdapter adapter = new DatabaseDataAdapterImpl();
List<DisplayDataThirdParty> legacyData = adapter.convertData(databaseData);
// Display the converted data
for (DisplayDataThirdParty data : legacyData) {
data.displayData();
}
}
}
Conclusion
The Adapter pattern is a versatile design pattern that allows seamless integration of disparate systems by bridging the interface gap. By converting one interface into another, it facilitates effective communication between components, making it a valuable tool in software development. Understanding and implementing the Adapter pattern can significantly enhance code reusability and maintainability.
In this article, we explored the fundamentals of the Adapter pattern and presented a practical example of its implementation in Java. Incorporating the Adapter pattern into your software architecture can open doors to smoother integration and more efficient communication between systems.
Happy coding!