Adapter Pattern
# Adapter Pattern
The Adapter Pattern acts as a bridge between two incompatible interfaces and is a structural design pattern. It converts the interface of one class into another interface that clients expect. This allows classes with incompatible interfaces to work together.
This pattern involves a single class, which is responsible for joining independent or incompatible interface functionalities. A real-world example is a card reader, which acts as an adapter between a memory card and a laptop. You insert the memory card into the card reader, then insert the card reader into the laptop, allowing the laptop to read the memory card.
Suppose we have an audio player that can only play MP3 files. Now, we need to play VLC and MP4 files. This can be achieved by creating an adapter:
* **Target Interface**: Defines an audio player interface that can play files of multiple formats.
* **Adaptee Class**: The existing audio player, which can only play MP3 files.
* **Adapter Class**: Create a new class that implements the target interface and uses the adaptee class internally to play MP3 files, while adding support for VLC and MP4 files.
## Overview
The Adapter Pattern is a software design pattern that aims to solve compatibility issues between different interfaces.
**Purpose**: Convert the interface of one class into another interface, allowing classes with incompatible interfaces to work together.
**Main Problem Solved**: In software systems, there is a need to integrate existing objects into a new environment, but the interface required by the new environment does not match the existing object.
### Use Cases
* You need to use an existing class, but its interface does not meet the system requirements.
* You want to create a reusable class that works with multiple unrelated classes (including those that might be introduced in the future), which may not have a unified interface.
* Integrate a class into another class hierarchy through interface conversion.
### Implementation Approach
* **Inheritance or Dependency**: It is recommended to use dependency rather than inheritance to maintain flexibility.
### Key Code
The adapter inherits from or depends on the existing object and implements the required target interface.
### Application Examples
* **Voltage Adapter**: Converts 110V voltage to 220V to adapt to electrical appliance standards in different countries.
* **Interface Conversion**: For example, converting the Enumeration interface from Java JDK 1.1 to the Iterator interface in 1.2.
* **Cross-Platform Execution**: Running Windows programs on Linux.
* **Database Connection**: In Java, JDBC uses the adapter pattern to interact with different types of databases.
### Advantages
* Promotes collaboration between classes, even if they have no direct association.
* Increases class reusability.
* Enhances class transparency.
* Provides good flexibility.
### Disadvantages
* Overuse of adapters can lead to a messy system structure, making it difficult to understand and maintain.
* In Java, since a class can only inherit from one class, it can only adapt one class, and the target class must be abstract.
### Usage Recommendations
* The Adapter Pattern should be used cautiously, especially during detailed design phases. It is more often used to solve problems in existing systems.
* When considering modifying a normally functioning system interface, the Adapter Pattern is a suitable choice.
In this way, the Adapter Pattern can clearly express its core concepts and applications while avoiding unnecessary complexity.
### Structure
The Adapter Pattern includes the following main roles:
* **Target Interface (Target)**: Defines the interface required by the client.
* **Adaptee Class (Adaptee)**: Defines an existing interface that needs to be adapted.
* **Adapter Class (Adapter)**: Implements the target interface and calls methods in the adaptee class through composition or inheritance, thereby achieving the target interface.
## Implementation
We have a _MediaPlayer_ interface and an entity class _AudioPlayer_ that implements the _MediaPlayer_ interface. By default, _AudioPlayer_ can play audio files in mp3 format.
We also have another interface _AdvancedMediaPlayer_ and entity classes that implement the _AdvancedMediaPlayer_ interface. These classes can play files in vlc and mp4 formats.
We want to allow _AudioPlayer_ to play audio files in other formats. To achieve this, we need to create an adapter class _MediaAdapter_ that implements the _MediaPlayer_ interface and uses _AdvancedMediaPlayer_ objects to play the required formats.
_AudioPlayer_ uses the adapter class _MediaAdapter_ to pass the required audio type, without needing to know the actual class that can play the audio in the required format. The _AdapterPatternDemo_ class uses the _AudioPlayer_ class to play various formats.

### Step 1
Create interfaces for the media player and the advanced media player.
## MediaPlayer.java
public interface MediaPlayer{public void play(String audioType, String fileName); }
## AdvancedMediaPlayer.java
public interface AdvancedMediaPlayer{public void playVlc(String fileName); public void playMp4(String fileName); }
### Step 2
Create entity classes that implement the _AdvancedMediaPlayer_ interface.
## VlcPlayer.java
public class VlcPlayer implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName){System.out.println("Playing vlc file. Name: "+ fileName); } @Override public void playMp4(String fileName){// Do nothing}}
## Mp4Player.java
public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName){// Do nothing} @Override public void playMp4(String fileName){System.out.println("Playing mp4 file. Name: "+ fileName); }}
### Step 3
Create an adapter class that implements the _MediaPlayer_ interface.
## MediaAdapter.java
public class MediaAdapter implements MediaPlayer{AdvancedMediaPlayer advancedMusicPlayer; public MediaAdapter(String audioType){if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer(); }else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player(); }} @Override public void play(String audioType, String fileName){if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName); }else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer.playMp4(fileName); }}}
### Step 4
Create an entity class that implements the _MediaPlayer_ interface.
## AudioPlayer.java
public class AudioPlayer implements MediaPlayer{MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName){// Built-in support for playing mp3 music files if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: "+ fileName); }// mediaAdapter provides support for playing other file formats else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); }else{System.out.println("Invalid media. "+ audioType + " format not supported"); }}}
### Step 5
Use AudioPlayer to play different types of audio formats.
## AdapterPatternDemo.java
public class AdapterPatternDemo{public static void main(String[]args){AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3", "beyond the horizon.mp3"); audioPlayer.play("mp4", "alone.mp4"); audioPlayer.play("vlc", "far far away.vlc"); audioPlayer.play("avi", "mind me.avi"); }}
### Step 6
Execute the program, and the output will be:
Playing mp3 file. Name: beyond the horizon.mp3 Playing mp4 file. Name: alone.mp4 Playing vlc file. Name: far far away.vlc Invalid media. avi format not supported
YouTip