Easy Understanding

웹 백엔드 관점으로 본 디자인 패턴 정리(7) - 어댑터 패턴(Adapter Pattern) 본문

Study

웹 백엔드 관점으로 본 디자인 패턴 정리(7) - 어댑터 패턴(Adapter Pattern)

appleg1226 2022. 5. 7. 14:55

 

어댑터 패턴

- 필요 개념: 컴포지션
- 활용도:가끔
- 난이도: 구현 자체는 간단함
- 패턴이 필요한 상황: 현재 개발한 코드와 비슷한 기능을 가진 다른 코드를 연동해야 할 때

어댑터 패턴은 그냥 사용하고 싶다고 사용할 수 있는 패턴은 아니다.

그 전제조건은 코드 자체가 오래되고 다양한 사람들이 개발하면서 쌓여온 소스코드여야 한다.

애초에 이 패턴은 이런 상황에 사용하는 것이다.

 

- 새로운 api를 개발하는데 비슷한 이전 코드가 존재하기는 한다. 그런데 뭔가 매개변수도 다르고 구조도 다르다.

- 여러 사람이 개발을 하는데 어쩌다보니 각자의 코드가 각자의 인터페이스를 갖고 있고 이게 도저히 수정할 수가 없는 구조다.

 

어댑터 패턴을 적용하는 것보다 더 좋은 것은 어댑터 패턴을 이용하지 않는 것이다.

인터페이스를 통합시킬 수 있다면 오히려 더 좋다.

오히려 이전 코드를 현재 코드의 형식대로 수정해서 사용할 수 있다면 좋다.

 

하지만 이전 소스코드가 수정하기엔 너무 복잡할 수도 있고,

여러 사정에 의해 다른 코드를 변경할 수 없는 상황이 있다.

그럴때 어댑터 패턴의 도입을 고려하면 된다. 

 

간단한 예시를 들고 넘어가겠다. 음악 플레이를 담당하는 클래스와 관련된 예시이다.

 

다음은 새롭게 개발하기로 결정한 NewMusicPlayer라는 인터페이스이다. 

interface NewMusicPlayer {
  playMusic(MusicPlayRequest request);
}

그런데 어쩌다보니 빠르게 개발을 해야만하는 비즈니스 요구사항이 들어온다.

그러면 어쩔 수 없이 기존 코드를 가져다 사용해야 한다. 그래서 기존 코드를 확인해본다.

class OldMusicPlayer {
  listenAudio(String musicName, int qualityType, ...){
    ...
  }
}

이 코드는 매개 변수가 위의 형태와 다르다. 

만약에 위의 인터페이스처럼 바꾸려면 저것들을 Request로 만들어 준 다음에,

그 request에서 내부 필드들을 꺼내서 기존 코드들을 수정해야 한다.

음.... 이러다간 시간안에 결과물을 내지 못할 것 같기도 하다.

그리고 실수가 생긴다면 코드가 깨질 위험성도 있다.

 

이럴 땐 컴포지션을 이용해서 생성자를 이용해 필드로 넣어서 사용하면 편리하다.

class NewMusicPlayerWithOldMusicPlayer implements NewMusicPlayer {
  private OldMusicPlayer oldMusicPlayer;
  
  public NewMusicPlayerWithOldMusicPlayer(OldMusicPlayer oldMusicPlayer){
    this.oldMusicPlayer = oldMusicPlayer; 
  }
  
  public void playMusic(MusicPlayRequest request){
    oldMusicPlayer.listenAudio(request.getName(), request.getQuality.toInt(), ...);
  }
}

이런 식으로 컴포지션을 이용해서 playMusic을 실행하도록 하지만 내부적으로는 listenAudio 메서드를 실행시킬 수가 있다.

 

저 길다란 이름 NewMusicPlayerWithOldMusicPlayer 을 줄여서 OldMusicPlayerAdapter 로 바꿔서 쓰면 된다.

이 간단한 게 어댑터 패턴이다.

 

정리하자면 비슷한 구현을 가진 호환되지 않은 클래스가 있을 경우 컴포지션을 이용해서 두 메서드를 이어주는 패턴이다.

클라이언트에서는 이러면 기존 기능에 대한 구현을 모르고도 새로운 인터페이스 구조로 코드를 사용할 수가 있다. 

 

이런 상황이 발생할 상황들은 생각보다 자주 있을 것이다.

예를들면 v1, v2 같이 api 버전이 늘어날 때 기존 메서드를 사용하고자 한다면 어댑터를 사용할만도 한 것 같다.

이걸 안쓰면 아마도 복붙해서 수정하게 될 것이고.

 

오래된 코드가 아닌데 프로젝트 중에 누군가가 어댑터 패턴을 쓰겠다고 한다면,

그 필요성에 대해서는 많이 토론해봐야할 것이다.