자바 디자인 패턴: 어댑터 패턴으로 인터페이스 호환성 확보하기

자바 디자인 패턴: 어댑터 패턴으로 인터페이스 호환성 확보하기

Adapter Pattern

소프트웨어 개발에서, 디자인 패턴은 문제를 해결하기 위한 일반적인 해결책입니다. 디자인 패턴은 공식적인 언어에서는 아니지만, 개발자들 사이에서 널리 사용되고 있습니다. 이번 글에서는 자바 디자인 패턴 중 어댑터 패턴에 대해 알아보겠습니다.

자바 디자인 패턴: 어댑터 패턴 소개

어댑터 패턴은 호환되지 않는 인터페이스를 함께 작동할 수 있도록 하는 디자인 패턴입니다. 이 패턴은 기존의 코드를 재사용하면서도 새로운 코드를 작성할 수 있도록 합니다. 어댑터 패턴은 일반적으로 두 가지 인터페이스 사이에서 작동합니다. 이 패턴은 "Wrapper 패턴"이라고도 불립니다.

어댑터 패턴은 다른 패턴과 함께 사용될 수 있습니다. 예를 들어, 어댑터 패턴은 데코레이터 패턴에서도 사용됩니다. 데코레이터 패턴은 객체에 추가적인 기능을 동적으로 추가하기 위한 패턴입니다. 데코레이터 패턴과 어댑터 패턴을 함께 사용하면, 객체에 새로운 기능을 추가하면서도 호환성 문제를 해결할 수 있습니다.

인터페이스 호환성 확보를 위한 어댑터 패턴 활용

어댑터 패턴은 인터페이스 호환성 문제를 해결하기 위해 사용됩니다. 다음은 인터페이스 호환성 문제의 예시입니다.

  • 서로 다른 라이브러리나 프레임워크에서 사용되는 클래스들이 있다.
  • 라이브러리나 프레임워크 A는 클래스 X를 사용하고, 라이브러리나 프레임워크 B는 클래스 Y를 사용한다.
  • 클래스 X와 Y는 서로 호환되지 않는다.
  • 이 경우, 클래스 X와 Y를 함께 사용하려면 어댑터 패턴을 사용해야 한다.

어댑터 패턴을 사용하면, 클래스 X와 Y를 함께 사용할 수 있습니다. 이를 위해서는 X와 Y를 호환되는 인터페이스로 변경해야 합니다. 이때, 어댑터 클래스를 사용합니다.

어댑터 클래스는 인터페이스를 구현하고, 호환되지 않는 클래스의 인스턴스를 감싸서, 인터페이스를 통해 호환성을 제공합니다. 이렇게 함으로써, 기존의 클래스를 수정하지 않고도 새로운 코드를 작성할 수 있습니다.

어댑터 패턴의 구조와 동작 방식

어댑터 패턴은 세 가지 주요 요소로 구성됩니다. 이들 요소는 다음과 같습니다.

  • Target: 호환성이 필요한 인터페이스입니다.
  • Adaptee: 호환성이 필요한 구현입니다.
  • Adapter: 호환성을 제공하는 클래스입니다.

Adapter Pattern Structure

Adaptee 클래스는 Target 인터페이스와 호환되지 않습니다. Adapter 클래스는 Adaptee 클래스를 감싸서, Target 인터페이스와 호환성을 제공합니다. 이를 통해, Adaptee 클래스를 Target 인터페이스를 사용하여 사용할 수 있습니다.

어댑터 패턴은 두 가지 방식으로 구현될 수 있습니다. 첫 번째 방법은 클래스 어댑터 패턴이고, 두 번째 방법은 객체 어댑터 패턴입니다.

클래스 어댑터 패턴

클래스 어댑터 패턴은 다중 상속을 사용하여 Target 인터페이스와 Adaptee 클래스를 동시에 상속하는 클래스를 만드는 방법입니다. 이 클래스는 Target 인터페이스를 구현하면서, Adaptee 클래스의 기능을 사용할 수 있습니다.

Class Adapter Pattern

클래스 어댑터 패턴은 다중 상속을 사용하기 때문에, Java와 같은 언어에서는 지원되지 않습니다.

객체 어댑터 패턴

객체 어댑터 패턴은 Target 인터페이스를 구현하는 클래스와 Adaptee 클래스를 각각 만드는 방법입니다. Adapter 클래스는 Target 인터페이스를 구현하면서, Adaptee 클래스의 인스턴스를 감싸서 사용합니다.

Object Adapter Pattern

객체 어댑터 패턴은 상속을 사용하지 않으므로, 클래스 어댑터 패턴과 달리 Java와 같은 언어에서 지원됩니다.

자바 어댑터 패턴 예제와 활용 사례

다음은 자바에서 어댑터 패턴을 사용하는 예시입니다.

public interface MediaPlayer {
   public void play(String audioType, String fileName);
}

public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

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
   }
}

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);   
   }
}

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);
      }
   }
}

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 

   @Override
   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");
      }
   }
}

위 예제는 오디오 파일을 재생하는 프로그램입니다. MediaPlayer 인터페이스는 mp3 파일을 지원합니다. 그러나, AdvancedMediaPlayer 인터페이스는 vlc와 mp4 파일을 지원합니다. 이 문제를 해결하기 위해, MediaAdapter 클래스가 사용됩니다.

MediaAdapter 클래스는 AdvancedMediaPlayer 인터페이스를 구현합니다. 이 클래스는 vlc와 mp4 파일을 지원하는 VlcPlayer와 Mp4Player 클래스의 인스턴스를 감싸서 사용합니다. AudioPlayer 클래스는 MediaPlayer 인터페이스를 구현하면서, MediaAdapter 클래스를 사용하여 vlc와 mp4 파일을 지원합니다.

결론

어댑터 패턴은 호환성 문제를 해결하기 위한 디자인 패턴입니다. 이 패턴을 사용하면, 호환되지 않는 인터페이스를 함께 작동할 수 있도록 합니다. 이를 위해서는 기존의 클래스를 수정하지 않고도 새로운 코드를 작성할 수 있습니다. 자바에서는 객체 어댑터 패턴을 사용하여 어댑터 패턴을 구현할 수 있습니다. 이 패턴은 라이브러리나 프레임워크에서 발생하는 호환성 문제를 해결하는데 유용합니다.