JAVA Developer Guide to start with Adapter Design Pattern
Imagine you are a chef who only knows how to cook pancakes. One day, a customer walks into your restaurant and orders a waffle. As a chef, you don’t know how to make waffles, but you don’t want to disappoint the customer. This is where the adapter design pattern comes in handy!
You can use a pancake-to-waffle adapter to solve the problem. The adapter acts as a bridge between the pancake (the existing class) and the waffle (the target class). You can use the pancake batter to make pancakes, but instead of pouring it into a pancake pan, you pour it into the adapter. The adapter will then use its own internal mechanisms to turn the pancake batter into a waffle.
Now you can serve the customer their desired waffle, even though you only know how to cook pancakes. And the customer will be happy because they got exactly what they wanted.
So, the adapter design pattern helps to make two incompatible classes work together, just like an adapter that converts pancake batter to waffles. Using this example, we can easily understand how the adapter design pattern can be used to adapt existing classes to meet new requirements.
What is the Adapter Pattern?
The Adapter Pattern is one of the structural design patterns from the book “Design Patterns: Elements of Reusable Object-Oriented Software”. An adapter pattern allows objects with incompatible interfaces to work together. It does so by wrapping the object that needs adaptation into a class that implements the desired interface. This new class is known as the adapter, and it acts as a bridge between the client and the adaptee object, converting requests from the original object (adaptee) into a format that the client can handle.
The Adapter Design Pattern can be used in a variety of contexts, such as when a class needs to be reused that doesn’t have the required interface or when a class needs to be used that has a different interface than what is expected. The pattern provides a flexible and elegant solution for these types of problems and makes it possible for objects to work together that would otherwise be incompatible.
Adapter Pattern JAVA Example
Let’s consider a scenario where gaming software is being developed and it has to support multiple gaming consoles like Xbox, PlayStation, and Nintendo. The software should be able to receive input from different gaming consoles and display the output on the screen. In this scenario, we can use the adapter design pattern to achieve compatibility between the gaming software and the different gaming consoles.
Target Interface Definition
We can define an interface called GamingConsole which would have methods for receiving input and displaying output. It will be our Target interface for the adapter design pattern example
Client Side Definition
We can define a class having ‘has-a’ dependency on the target interface, along with a required method to play with GamingConsole objects.
Adaptee Object Definition
Next, we can define adaptee concrete classes for each gaming console that we have to use in our gaming software. These classes will contain the specific implementation details for each gaming console. If we observe these adaptee classes, these are not implementing the target interface GamingConsole, hence these can’t be used with the client directly.
Adapter Classes Definition
We can define the adapter class for each gaming console that implements the target interface GamingConsole. This adapter class will adapt the specific implementation of each gaming console adaptee while implementing methods from GamingConsole interface.
Adapter Pattern in Action
In the demo code below, created a client, and three adaptee along with respective adapters. The gaming software does not need to be aware of the specific implementation details of each gaming console, as it only interacts with the adapter class which implements the GamingConsole interface. This allows for easy integration of new gaming consoles in the future and makes the software more flexible and maintainable.
Source Code Available at: https://github.com/s3c-d43m0n/Desing-Patterns-in-JAVA/tree/main/Structural/Adapter
Key Points in the Implementation
- Identify the Target Interface:
This is the interface that the client code expects to use. It defines the methods that the client requires. - Identify the Adaptee Class:
This is the class that needs to be adapted to meet the target interface requirements. - Create the Adapter Class:
This is the class that implements the target interface and delegates calls to the adaptee class. It acts as a bridge between the client and the adaptee. - Use Composition:
The adapter class should use composition to hold an instance of the adaptee class. This allows the adapter to delegate calls to the adaptee. - Implement the Target Interface Methods:
The adapter class must implement all of the methods defined in the target interface. These methods should delegate calls to the adaptee class. - Test the Adapter:
Verify that the adapter class works as expected by testing it with client code. Ensure that client code can use the adapter class as if it were the target interface, without having to change any of its code. - Update Client Code If necessary:
The client code should be unaware that it is using an adapter, and should work seamlessly with the adapter class. Usually, we don’t change the client code, but if requires then update client code to use the target interface using “has a” relationship.
What’s your favorite design pattern or if you’d like to understand better any other pattern or topic, feel free to reach out to me on LinkedIn or Google Form and I’ll try to cover it next time!
Please share this with all your Medium friends and hit that👏 button below to spread it around even more. Please follow me for future updates. Thanks for reading.