Adapter Pattern

 Intent:

Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.

It converts the interface of a class into another interface as clients expect without changing the existing code. Wrap an existing class with a new interface.

When to use, 

You have developed Audio player application which supports mp3 audio format. Now new requirement added to extend the audio format support to include WAV, AAC file. You have decided to use third party library to play the wav, aac files. But, third party library interfaces are not matching with the existing IAudioPlayer interface which was delivered to the customer. 

How to use IAdvancedAudioPlayer without modifying the IAudioPlayer interfaces ?

Our intention is to extend the audio format support but without modifying the existing interface class interface functions. 
Adding adapter class resolves this issue. 

UML Diagram:
Source: refactoring guru




















Implementation:

Sourcecode: https://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/AdapterPattern/AdapterPattern.hpp

This implementation uses the object composition principle: the adapter implements the interface of one object and wraps the other one. 



































1. Interface class:

Defined IAudioPlayer interface class which has pure virtual method to play audio. The class implements it provides the definition this method.

//AudioPlayer Interfacce class
class IAudioPlayer
{
public:
    virtual void play(string format, string audioFilePath) = 0;
};

2. Concrete class:

CAudioPlayer class derived from the interface class. This class has functionality to play mp3 audio files. It has definition of the pure virtual method in the interface class. 
It has adapter class object. When CAudioPlayer receives the request to play the audio formats which supported by third party interface class, it will invoke the adapter class "play" function.
//Audio Player
class CAudioPlayer : public IAudioPlayer
{
private:
    //Adapter instance
    CAdapter* adapter;

    //Get the apapter instance
    CAdapter* getAdapter()
    {
        if (nullptr == adapter)
        {
            adapter = new CAdapter;
        }
        return adapter;
    }
public:
    CAudioPlayer()
    {
        adapter = nullptr;
    }
    //Implementation of the pure virtual function
    void play(string format, string audioFile) override
    {
        if ("mp3" == format)
        {
            cout << " Audioplayer is playing MP3 song " << audioFile << endl;
        }
        else
        {
            //pass the request to the adapter class for further handling
            getAdapter()->play(format, audioFile);
        }
    }
};

3. Adapter class:

Adapter class contains the object of the third party library interface class (IAdvancedAudioPlayer).
Based on the audio formats from the user, adapter class invokes the "playAudio" function from IAdvancedAudioPlayer to play wav and aac audio files.

//Adapter class
//Derived from the interface class
class CAdapter : public IAudioPlayer
{
    private:
    //contains the object of the AdvancedAudioPlayer
    IAdvancedAudioPlayer* advancedPlayer;

    public:
    //Implementation of the pure virtual function
    void play(string format, string audioFile) override
    {
        if("wav" == format)
        {
            cout<<"WAV file - passing the request to the advanced player "<<endl;
            advancedPlayer = new CWAVAudio;
            advancedPlayer->playAudio(IAdvancedAudioPlayer::eAudioFormats::eWAV, audioFile);
        }
        else if("aac" == format)
        {
            cout<<"AAC File - passing the request to the advanced player "<<endl;
            advancedPlayer = new CAACAudio;
            advancedPlayer->playAudio(IAdvancedAudioPlayer::eAudioFormats::eAAC, audioFile);
        }
        else
        {
            cerr<<" wrong audio format "<<format<<endl;
        }
    }
};

4. Advanced audio player class. 

IAdavancedAudioPlayer class contains the pure virtual function. CWAVAudio, CAACAudio classes are derived from IAdvancedAudioPlayer class , it has the implementation of the interface function to play wav and aac audio formats.
//Interface class for advanced audio player
class IAdvancedAudioPlayer
{
public:
    //supported audio formats
    enum eAudioFormats
    {
        eWAV = 0,
        eAAC
    };
    virtual void playAudio(eAudioFormats audioFormat, string audioFile) = 0;
};

//Wav audio player
class CWAVAudio : public IAdvancedAudioPlayer
{
private:
    void playWavFile(string filePath)
    {
        cout << "AdvancedAudioPlayer is playing WAV audio file" << endl;
    }
public:
    void playAudio(eAudioFormats audioFormat, string audioFile) override
    {
        playWavFile(audioFile);
    }
};

//AAC audio player
class CAACAudio : public IAdvancedAudioPlayer
{
private:
    void playAacFile(string filePath)
    {
        cout << "AdvancedAudioPlayer is playing AAC audio file" << endl;
    }
public:
    void playAudio(eAudioFormats audioFormat, string audioFile) override
    {
        playAacFile(audioFile);
    }
};

5. Client code:

Client is only aware of the IAudioPlayer interface class.  It invokes "play" function and sends the audio format , audio file path as selected by the user. 

//client code
IAudioPlayer* audioPlayer = new CAudioPlayer;
audioPlayer->play("wav","c:/audio1.wav");
audioPlayer->play("mp3","c:/audio2.mp3");
audioPlayer->play("aac","c:/audio3.aac");
audioPlayer->play("mp4", "c:/audio3.aac");

Output:

WAV file - passing the request to the advanced player AdvancedAudioPlayer is playing WAV audio file Audioplayer is playing the song c:/audio2.mp3 AAC File - passing the request to the advanced player AdvancedAudioPlayer is playing AAC audio file wrong audio format mp4