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");
}
}