The Adapter Pattern is the first structural pattern we will discuss. It allows two classes or systems having incompatible interfaces to work together. Essentially it acts as a middle layer by wrapping an existing class with a new interface making it compatible with the client’s interface.

Structure

The Adapter pattern consists of the following key components:

  • Target Interface: is the interface which the client uses or expects
  • Adaptee: is the existing incompatible class or component which needs to be made compatible with the Target Interface
  • Adapter: is the class which adapts the Adaptee to the Target Interface
  • Client: uses Target Interface to interact with the Adapter

When to use the Adapter Pattern?

  • When you want to use existing classes having incompatible interfaces
  • When you want to separate preprocessing code from primary business logic code (Single Responsibility Principle)
  • When you want to add new functionality/adapters to the application without making changes to the existing logic (Open/Closed Principle)

Implementation Example

The code below demonstrates the implementation of the Adapter design pattern in Java. The code showcases the Adapter pattern, where the MediaAdapter acts as an adapter between the MediaPlayer interface and the WAVPlayer class, allowing the AudioPlayer to play both MP3 and WAV files without modifying the existing code.

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

        audioPlayer.play(".mp3", "hello.mp3");
        audioPlayer.play(".wav", "world.wav");
        audioPlayer.play(".mp4", "helloworld.mp4");
    }
}

// target interface
interface MediaPlayer {

    public void play(String audioType, String fileName);
}

// class following target interface
class MP3Player implements MediaPlayer {

    public void play(String audioType, String fileName) {

        if (audioType.equals(".mp3")) {

            System.out.println("Playing MP3 File: " + fileName);
        } else {

            System.out.println("Invalid media format, can only play MP3 files!");
        }
    }
}

// adaptee class
class WAVPlayer {

    public void playWAV(String fileName) {

        System.out.println("Playing WAV File: " + fileName);
    }
}

// adapter
class MediaAdapter implements MediaPlayer {

    public WAVPlayer wavPlayer;

    public MediaAdapter(String audioType) {

        if (audioType.equals(".wav")) {
            
            wavPlayer = new WAVPlayer();
        }
    }

    public void play(String audioType, String fileName) {

        if (audioType.equals(".wav")) {

            System.out.println("Playing WAV File: " + fileName);
        } else {

            System.out.println("Invalid media format, can only play WAV files!");
        }
    }
}

// concrete class implementing target interface
class AudioPlayer implements MediaPlayer {

    private MediaAdapter mediaAdapter;

    public void play(String audioType, String fileName) {
        
        if (audioType.equalsIgnoreCase(".mp3")) {
            
            MP3Player mp3Player = new MP3Player();
            mp3Player.play(audioType, fileName);
        } else if (audioType.equalsIgnoreCase(".wav")) {
            
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            
            System.out.println("Invalid media type. AudioPlayer can only play MP3 and WAV files.");
        }
    }
}

The output of the following program will be:

Playing MP3 File: hello.mp3
Playing WAV File: world.wav
Invalid media type. AudioPlayer can only play MP3 and WAV files.