Design Patterns - Adapter

design-patterns

// Design Patterns - Structural - Adapter:

Adapter pattern works as a bridge between two incompatible interfaces. This 
type of design pattern comes under structural pattern as this pattern combines 
the capability of two independent interfaces.

// Step 1: Create interfaces for Media Player and Advanced Media Player.
public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {    
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

// Step 2: Create concrete classes implementing the AdvancedMediaPlayer interface.
public class VlcPlayer implements AdvancedMediaPlayer{
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);        
   }
   public void playMp4(String fileName) {
      //do nothing
   }
}

public class Mp4Player implements AdvancedMediaPlayer{
   public void playVlc(String fileName) {
      //do nothing
   }
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);        
   }
}

// Step 3: Create adapter class implementing the MediaPlayer interface.
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 concrete class implementing the MediaPlayer interface.
public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 

   public void play(String audioType, String fileName) {
      //inbuilt support to play mp3 music files
      if (audioType.equalsIgnoreCase("mp3")) {
         System.out.println("Playing mp3 file. Name: " + fileName);            
      } 

      //mediaAdapter is providing support to play 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 the AudioPlayer to play different types of audio formats.
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");

What is the purpose of the Adapter pattern?

The Adapter pattern is a design pattern which is commonly used to manage changes in development.

In computer programming, the adapter pattern is a design pattern that translates one interface for a class into a compatible interface.An adapter allows classes to work together that normally could not because of incompatible interfaces, by providing its interface to clients while using the original interface.

In the physical world, we have adapters for our electronic devices such as a bluetooth to USB adapter where we have a bluetooth device but our computer does not directly support bluetooth, but does support USB, we can purchase a bluetooth-USB adapter.

In the software world, we may need to use the adapter pattern if the service that we depends on had decided to make incompatible changes to its API. In such cases, we may need to make an adapter which makes the old interface works with the new interface.

When we deal with an external services, we should implement our own internal API for dealing with this external API, so if the external API is changed, we only have to modify the implementation of our internal API instead of the internal API itself or the rest of our application. The Facade pattern fit well for this purpose. If we have a class on our end for dealing with the old API, perhaps we can implement an adapter that adapt the old class to the new API.

In the software world, we may also need to use the adapter pattern when we wish to change the service providers. For example, we may wish to change from using MailChimp to SendGrid where the provider may offer different APIs such as sending through HTTPS instead of regular SMTP.

adapt-03.jpg

Usually we have a Client, Target, and Adaptee in our application, and the Adaptee class implements the Target interface. We should create and use the Target interface ahead of time before we even need it.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License