[Java design pattern series] Adapter mode and detailed explanation of applicable scenarios

1 Motivation

Similar to the design and coding skills of power adapters. Generally, the client accesses the services it provides through the interface of the target class.
Sometimes, the existing class can meet the needs of the customer class, but the provided interface is not necessarily what the customer class expects, possibly because the method name in the existing class is inconsistent with the method name defined in the target class

At this time, the existing interface needs to be transformed into the interface expected by the client class to ensure that the existing class
is reused. If such a conversion is not carried out, the client class cannot use the functions provided by the existing class, and the adapter pattern can complete such a conversion.

A wrapper class can be defined in the adapter mode to wrap objects that are not compatible with the interface

  • The packaging class refers to the adapter (Adapter)
  • The packaged object is the Adaptee (Adaptee), that is, the adapted class

The adapter provides the interface required by
the client class. The realization of the adapter is to convert the request of the client class into a call to the corresponding interface of the adaptor. That is, when the client class calls the method of the adapter, the method of the adapter class will be called inside the adapter class, and this process is transparent to the client class, and the client class does not directly access the adapter class. Therefore, the adapter can make classes that cannot interact due to incompatible interfaces work together

2 definition

Convert an interface into another interface that the customer wants, so that those classes that are incompatible with the interface can work together, and its alias is wrapper. It
can be used as a class structure pattern or an object structure pattern.

3 structure

  • Target: target abstract class
  • Adapter: Adapter class
  • Adaptee: adaptor class
  • Client: client class

The adapter mode has two implementations: object adapter and class adapter:

3.1 Object adapter

3.2 Class adapter

#4 Timing diagram

5 code analysis

achieve

  • MediaPlayer interface
  • The entity class AudioPlayer that implements the MediaPlayer interface

By default, AudioPlayer can play mp3

  • Interface AdvancedMediaPlayer
  • The entity class that implements the AdvancedMediaPlayer interface. This class can play files in vlc and mp4 formats.

We want to let AudioPlayer play audio files in other formats. In order to achieve this function, we need to create

  • An adapter class MediaAdapter that implements the MediaPlayer interface

use

  • AdvancedMediaPlayer object to play the required format.

AudioPlayer uses the adapter class MediaAdapter to pass the required audio type, and does not need to know the actual class that can play the required format audio. AdapterPatternDemo , our demo class uses the AudioPlayer class to play various formats.

UML diagram of the adapter pattern

step 1

Create interfaces for media players and more advanced media players.

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 an entity class that implements 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) {
      //什么也不做
   }
}

Mp4Player.java

public class Mp4Player implements AdvancedMediaPlayer{

   @Override
   public void playVlc(String fileName) {
      //什么也不做
   }

   @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) {        

      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);            
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      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

Verify the output.

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

Case study

Realization Iterableof Fibnoaccigenerators

Rewrite the class that implements Iterablethe interface?

  • But you don’t always have control of the source code
  • And, unless we have to do this, otherwise, we are not willing to rewrite a class

So another option, create a adapter (Adapter) to implement the required interfaces

There are multiple implementations of adapters. For example inheritance:

In the for-in using the statement IterableFibonacci, you must provide a boundary value in the constructor, so hasNext()know when to return false , the loop ends.

8 advantages

  • Decouple the target class and the adaptor class, and reuse the existing adaptor class by introducing an adaptor class without modifying the original code.
  • Increase the transparency and reusability of the class, encapsulate the specific implementation in the adaptor class, which is transparent to the client class, and improve the reusability of the adaptor.
  • Flexibility and scalability are very good. Through the use of configuration files, the adapter can be easily replaced, and new adapter classes can be added without modifying the original code, which is fully in line with the "opening and closing principle".

The class adapter pattern also has the following advantages:
because the adapter class is a subclass of the adapter class, some adapter methods can be replaced in the adapter class, making the adapter more flexible.
The object adapter pattern also has the following advantages:
an object adapter can adapt multiple different adaptors to the same target, that is, the same adaptor can adapt the adaptor class and its subclasses to the target interface.

9 Disadvantages

Class adapter pattern

For languages ​​that do not support multiple inheritance, such as Java and C#, at most one adaptor class can be adapted at a time, and the target abstract class can only be an abstract class, not a concrete class, and its use has certain limitations. The adaptor class and its subclasses are adapted to the target interface.

Object adapter pattern

Compared with the class adapter pattern, it is not easy to replace the method of the adapter class. If you must replace one or more methods of the adaptor class, you have to make a subclass of the adaptor class first, replace the methods of the adaptor class, and then treat the subclass of the adaptor class as The real adaptor performs adaptation, and the implementation process is more complicated.

10 Applicable environment

Adapter mode can be used in the following situations:

  • The system needs to use existing classes, and the interfaces of these classes do not meet the needs of the system.
  • I want to create a reusable class to work with some classes that are not very related to each other, including some classes that may be introduced in the future.

11 mode application

Sun company released the Java language database connection tool JDBC in 1996. JDBC enables Java language programs to connect to the database and uses SQL language to query and manipulate data. JDBC provides a general abstract interface for the client. The JDBC driver software of each specific database engine (such as SQL Server, Oracle, MySQL, etc.) is an adapter software between the JDBC interface and the database engine interface. Corresponding adapter software is required between the abstract JDBC interface and each database engine API. This is the driver for each different database engine.

12 mode extension

Adapter recognition mode (Default Adapter Pattern) adapter or the default mode
when no interface provides all of the method when implemented, can be designed to abstract class implements an interface and provide a realization (empty method) The default method for each interface, Then the subclasses of this abstract class can selectively override some methods of the parent class to achieve the requirements. It is suitable for situations where an interface does not want to use all of its methods. Therefore, it is also called the single-interface adapter mode.

13 Summary

  • Structural pattern: describes how to combine classes or objects to form a larger structure.
    The adapter pattern is used to convert an interface into another interface that the customer wants. The adapter pattern enables classes that are incompatible with the interface to work together, and its alias is a wrapper. The adapter pattern can be used as either a class structure pattern or an object structure pattern.
  • The adapter pattern contains four roles: the target abstract class defines the interface of the specific domain to be used by the customer; the adapter class can call another interface as a converter to adapt the adapter and the abstract target class. It is the adapter pattern Core; the adaptor class is the role to be adapted, it defines an existing interface, this interface needs to be adapted; in the client class for the target abstract class to program, call the business method defined in the target abstract class.
  • In the class adapter mode, the adapter class implements the target abstract class interface and inherits the adapter class, and calls the method of the inherited adapter class in the implementation method of the target abstract class; in the object adapter mode, the adapter class The target abstract class is inherited and an object instance of the adaptor class is defined, and the corresponding business method of the adaptor class is called in the inherited target abstract class method.
  • The main advantage of the adapter pattern is to decouple the target class and the adaptor class, which increases the transparency and reusability of the class. At the same time, the flexibility and scalability of the system are very good. It is very convenient to replace the adapter or add a new adapter. , In line with the "opening and closing principle"; the disadvantage of the class adapter pattern is that the adapter class cannot adapt to multiple adapter classes at the same time in many programming languages. The disadvantage of the object adapter pattern is that it is difficult to replace the method of the adapter class.
  • The application of the adapter pattern includes: the system needs to use existing classes, and the interfaces of these classes do not meet the needs of the system; want to create a reusable class for use with some classes that are not very related to each other jobs.