Adapter Pattern
The Adapter design pattern allows incompatible interfaces to work together by acting as a bridge between them.
It converts the interface of one class into another interface that clients expect. In simple terms, think of it as a plug adapter that lets you connect a device with one type of plug to a power outlet with a different type of socket.
Think of it as using an adapter to plug a European electrical device (with a European plug) into a US power outlet (with a US plug). The adapter converts the European plug into a US plug, enabling the device to function correctly.
The Adapter pattern helps achieve interoperability between classes that otherwise wouldn’t be able to work together due to their incompatible interfaces.
Table of Contents
Adapter Pattern C++ Example:
Let’s consider a MediaPlayer
interface that represents various media players, and a legacy OldMediaPlayer
class with an incompatible interface. We’ll create an Adapter
class to make the OldMediaPlayer
work with the MediaPlayer
interface.
Adapter Pattern Example Class Diagram:
+---------------+
| MediaPlayer |
+---------------+
| + play() |
+-------^-------+
|
|
+----------+-----------+
| |
+---------------+ +------------------+
| MP3Player | | OldMediaPlayer |
+---------------+ +------------------+
| + play() | | + playOld() |
+---------------+ +------------------+
^
|
+-------+-------+
| |
+----------------+ +------------------+
| MediaPlayerAdapter |
+----------------+ +------------------+
| - oldPlayer: OldMediaPlayer* |
| + play() |
| - convertToOldFormat() |
+----------------+
#include <iostream>
#include <string>
// MediaPlayer interface
class MediaPlayer {
public:
virtual void play(std::string filename) = 0;
};
// Concrete MediaPlayer implementation: MP3Player
class MP3Player : public MediaPlayer {
public:
void play(std::string filename) override {
std::cout << "Playing MP3 file: " << filename << std::endl;
}
};
// Legacy OldMediaPlayer class with incompatible interface
class OldMediaPlayer {
public:
void playOld(std::string oldFilename) {
std::cout << "Playing old media file: " << oldFilename << std::endl;
}
};
// Adapter class that adapts OldMediaPlayer to the MediaPlayer interface
class MediaPlayerAdapter : public MediaPlayer {
public:
MediaPlayerAdapter(OldMediaPlayer* oldPlayer)
: oldPlayer_(oldPlayer) {}
void play(std::string filename) override {
// Converting the filename to the old format (if needed)
std::string oldFilename = convertToOldFormat(filename);
oldPlayer_->playOld(oldFilename);
}
private:
OldMediaPlayer* oldPlayer_;
// Helper method to convert the filename to old format
std::string convertToOldFormat(std::string filename) {
// For simplicity, we just append "_old" to the filename
return filename + "_old";
}
};
int main() {
// Using the MP3Player (compatible with MediaPlayer interface)
MediaPlayer* mp3Player = new MP3Player();
mp3Player->play("song.mp3");
// Using the OldMediaPlayer through the adapter
OldMediaPlayer* oldPlayer = new OldMediaPlayer();
MediaPlayerAdapter* adapter = new MediaPlayerAdapter(oldPlayer);
adapter->play("old_song.mp4");
delete mp3Player;
delete adapter;
delete oldPlayer;
return 0;
}
Adapter Pattern C++ Explanation:
In this example, we have a MediaPlayer
interface with a method play()
that takes the filename of the media to play. The MP3Player
class is a concrete implementation of the MediaPlayer
interface, and it can play MP3 files.
Next, we have the OldMediaPlayer
class, which represents a legacy media player with an incompatible interface. It has a method playOld()
that takes the old filename format as input.
To make the OldMediaPlayer
compatible with the MediaPlayer
interface, we create an MediaPlayerAdapter
class. This class inherits from the MediaPlayer
interface and holds a pointer to the OldMediaPlayer
instance. The play()
method of the adapter takes the filename in the new format, converts it to the old format using a helper method convertToOldFormat()
, and then calls the playOld()
method of the OldMediaPlayer
to play the media in the old format.
In the main()
function, we demonstrate how the Adapter pattern works. We first use the MP3Player
(which is compatible with the MediaPlayer
interface) to play an MP3 file. Then, we use the OldMediaPlayer
through the MediaPlayerAdapter
to play an old media file, and the adapter converts the filename to the old format before passing it to the OldMediaPlayer
.
Adapter Pattern Summary:
The Adapter pattern allows objects with incompatible interfaces to work together by creating an adapter class that adapts the interface of one class to another. In this example, the MediaPlayerAdapter
makes the OldMediaPlayer
compatible with the MediaPlayer
interface, allowing it to work with other media players seamlessly. The Adapter pattern promotes code reusability and enables the integration of legacy code or third-party libraries into your application with ease.