📝 What You’ll Learn

  • What the Adapter Pattern is
  • Why it’s useful for integrating incompatible interfaces
  • How to implement it in Java
  • Real-world examples and analogies
  • Pitfalls and best practices

🔍 What Is the Adapter Pattern?

The Adapter Pattern allows incompatible classes to work together by translating one interface into another.

Think of it like a power plug adapter — it connects two mismatched systems so they can communicate.

🔁 When to Use It

Use the Adapter Pattern when:

  • You need to use an existing class but its interface doesn’t match what you need
  • You want to integrate legacy code with a new system
  • You’re building a reusable system that requires interface flexibility

🧱 Java Implementation

🧩 Scenario

You have a MediaPlayer interface that expects to play audio files, but a third-party AdvancedMediaPlayer supports different methods.

🎧 Interfaces and Classes

// Target interface
public interface MediaPlayer {
    void play(String audioType, String fileName);
}
// Adaptee (incompatible class)
public class AdvancedMediaPlayer {
    public void playMp4(String fileName) {
        System.out.println("Playing MP4 file: " + fileName);
    }

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

🔌 Adapter Class

public class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedPlayer = new AdvancedMediaPlayer();

    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("vlc")) {
            advancedPlayer.playVlc(fileName);
        } else if(audioType.equalsIgnoreCase("mp4")) {
            advancedPlayer.playMp4(fileName);
        } else {
            System.out.println("Invalid format: " + audioType);
        }
    }
}

✅ Usage

public class AudioPlayer implements MediaPlayer {
    private MediaAdapter adapter;

    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing MP3 file: " + fileName);
        } else {
            adapter = new MediaAdapter();
            adapter.play(audioType, fileName);
        }
    }
}
AudioPlayer player = new AudioPlayer();
player.play("mp3", "song.mp3");
player.play("mp4", "video.mp4");
player.play("vlc", "movie.vlc");

🔌 Real-World Analogy

Imagine you’re traveling abroad. Your laptop plug doesn’t fit the socket — so you use a travel adapter to bridge the gap. Same device, compatible through conversion.

⚠️ Pitfalls to Avoid

  • ❌ Creating overly complex adapters for very simple integrations
  • ❌ Ignoring the performance cost of adapting at runtime
  • ❌ Confusing it with the Decorator or Facade pattern

✅ Best Practices

  • Keep adapter logic simple and focused
  • Prefer composition over inheritance
  • Use adapters for interface compatibility, not behavior changes

📘 Recap

  • Adapter Pattern helps classes with incompatible interfaces work together
  • It wraps one class in another to translate interfaces
  • Very useful for integrating third-party or legacy systems
  • Real-world analogy: plug adapters, USB dongles, language translators