Skip to main content

The Adapter Pattern

Category: Structural

The Adapter pattern acts as a bridge between two incompatible interfaces. It allows objects with incompatible interfaces to collaborate.

Think of a real-world power adapter: If you travel from the US to Europe, your laptop plug won't fit into the wall socket. You use a power adapter that plugs into the European socket and provides a US-style socket for your laptop. The Adapter pattern does exactly this in software.


Example: The Media Player​

Imagine you have a modern AudioPlayer that can only play .mp3 files. You are given an advanced, third-party library that can play .vlc and .mp4 files, but its interface is completely different.

You cannot change the third-party library code. How do you make your AudioPlayer use it? You build an Adapter!

1. The Target Interface​

This is the interface your client code understands and expects.

public interface MediaPlayer {
void play(String audioType, String fileName);
}

2. The Incompatible (Adaptee) Interface​

This is the third-party library you want to use, but its interface doesn't match MediaPlayer.

public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}

public class VlcPlayer implements AdvancedMediaPlayer {

@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file: " + fileName);
}

@Override
public void playMp4(String fileName) {
// Do nothing
}
}

3. The Adapter​

This class implements the interface your client expects (MediaPlayer), but inside its methods, it translates the call and passes it to the incompatible object (AdvancedMediaPlayer).

public class MediaAdapter implements MediaPlayer {

// The Adapter holds a reference to the incompatible object
AdvancedMediaPlayer advancedMusicPlayer;

// Constructor determines which advanced player to use
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
}
// (Could add MP4 player here too)
}

// Translating the client's play() call into the advanced player's specific calls
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
}
}
}

4. The Client Implementation​

Now your core AudioPlayer can use the Adapter to play formats it originally couldn't understand!

public class AudioPlayer implements MediaPlayer {

MediaAdapter mediaAdapter;

@Override
public void play(String audioType, String fileName) {
// Inbuilt support for mp3
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file: " + fileName);
}
// mediaAdapter is providing support to play other file formats
else if (audioType.equalsIgnoreCase("vlc")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println(
"Invalid media. " + audioType + " format not supported"
);
}
}
}

5. Running the Code​

public class LabAdapter1 {

public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();

audioPlayer.play("mp3", "beyond_the_horizon.mp3");

// The AudioPlayer successfully plays a VLC file using the Adapter!
audioPlayer.play("vlc", "far_far_away.vlc");
}
}