Adapter Design Pattern
The Adapter Design Pattern is a structural design pattern used in object-oriented programming. It helps two incompatible interfaces work together without changing their existing code.
In simple words, an adapter acts like a bridge between two different systems. Just like a mobile charger adapter allows you to charge your phone using a different socket, this pattern allows classes with different interfaces to communicate.
Why Do We Need the Adapter Pattern?
Many times, we work with:
- Legacy code that we cannot modify
- Third-party libraries with fixed interfaces
- New systems that must work with old systems
Instead of changing existing code (which may be risky or impossible), we create an adapter that converts one interface into another.
Real-Life Example
Imagine you have a music player that supports only MP3 files, but now you want to play MP4 or VLC files.
Instead of changing the music player itself, you create an adapter that converts MP4 or VLC files into a format the player understands.
Adapter Pattern Example in Java
Step 1: Create the Target Interface
This is the interface expected by the client.
interface MediaPlayer {
void play(String audioType, String fileName);
}
Step 2: Create an Existing (Incompatible) Interface
This interface already exists and cannot be changed.
interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
Step 3: Create Concrete Implementations
class VlcPlayer implements AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("Playing VLC file: " + fileName);
}
public void playMp4(String fileName) {
// Not supported
}
}
class Mp4Player implements AdvancedMediaPlayer {
public void playVlc(String fileName) {
// Not supported
}
public void playMp4(String fileName) {
System.out.println("Playing MP4 file: " + fileName);
}
}
Step 4: Create the Adapter Class
This class adapts AdvancedMediaPlayer to MediaPlayer.
class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer = new Mp4Player();
}
}
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer.playMp4(fileName);
}
}
}
Step 5: Create the Client Class
class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing MP3 file: " + fileName);
}
else if (audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else {
System.out.println("Invalid media type: " + audioType);
}
}
}
Step 6: Test the Adapter Pattern
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "song.mp3");
audioPlayer.play("mp4", "video.mp4");
audioPlayer.play("vlc", "movie.vlc");
audioPlayer.play("avi", "file.avi");
}
}
Output
Playing MP3 file: song.mp3 Playing MP4 file: video.mp4 Playing VLC file: movie.vlc Invalid media type: avi
Key Advantages of Adapter Design Pattern
- Allows incompatible interfaces to work together
- Improves code reusability
- Follows Open/Closed Principle
- Avoids modifying existing or legacy code
When Should You Use Adapter Pattern?
- When existing classes cannot work with new interfaces
- When using third-party libraries with different APIs
- When migrating old systems to new systems
Conclusion
The Adapter Design Pattern is a simple yet powerful solution to make incompatible systems work together. By using an adapter, you keep your code clean, flexible, and easy to maintain.
It is widely used in real-world Java applications, frameworks, and APIs.