2. 어댑터 패턴 (Adapter Pattern)

728x90

저번 강의 [디자인 패턴] - 1. 전략(Strategy) 패턴 에 이어서 이번 포스팅에는 '어댑터 패턴'에 대한 내용을 정리하고자 한다.

어댑터 패턴이란... 

어댑터 패턴은 연관성이 없는 두 객체를 묶어 사용할 때 쓰이는 패턴이다. (= 클라이언트가 요구하는 인터페이스와 재사용하려는 모듈의 인터페이스가 일치하지 않을 때 사용할 수 있는 패턴)

어댑터 패턴이 적용된 예는 SLF4J라는 로깅 API이다. SLF4J는 단일 로깅 API를 사용하면서 자바 로깅, log4j, LogBack 등의 로깅 프레임워크를 선택적으로 사용할 수 있도록 해 주는데, 이 때 SLF4J가 제공하는 인터페이스와 각 로깅 프레임워크를 맞춰 주기 위해 어댑터를 사용하고 있다. 

어댑터 패턴은 (SOLID 원칙에서 OCP)개방 폐쇄 원칙을 따를 수 있도록 도와준다. (예를들어 로깅 프레임워크를 LogBack으로 교체하고 싶다면 LogBack을 slf4j-api 패키지의 Logger로 맞춰주는 새로운 어댑터만 구현해 주면 된다. 그리고 이 과정에서 slf4j-api 패키지의 Logger를 사용하는 코드는 전혀 영향을 받지 않는다)

 

예제 

웹 게시판에 통합 검색 기능을 추가해 달라는 요구가 들어와서 DB를 이용해서 검색 기능을 구현하기로 결정한 상황을 생각해 보자. 통합 검색 기능을 정의하기 위해 아래와 같이 SearchService 인터페이스를 작성하고, DB를 이용한 DBSearchService 클래스를 구현하였다. 

 

게시글의 개수가 빠르게 증가하면서 SQL의 like를 이용한 검색 속도 성능에 문제가 발생하기 시작했다. 검색 속도의 문제를 해결하기 위해 Tolr라는 오픈 소스 검색 서버를 도입하기로 결정했다. Tolr와 쉽게 연동할 수 있다는 것을 알게 되었다.

문제는 TolrClient가 제공하는 인터페이스와 SearchService 인터페이스가 맞지 않는다는 점이다. WebSearchRequestHandler 클래스를 비롯해서 여러 클래스가 SearchService를 사용하도록 만들어졌기 때문에, SearchService 대신 TolrService를 사용하도록 변경하는 작업은 많은 변경을 요구한다.

이렇게 클라이언트(WebSearchRequestHandler)가 요구하는 인터페이스(SearchService)와 재사용하려는 모듈의 인터페이스(TolrClient)가 일치하지 않을 때 사용할 수 있는 패턴 어댑터(Adapter) 패턴이다. 인터페이스가 맞지 않는 문제를 해결하기 위해 어댑터 패턴을 적용하면 아래와 같은 구조를 갖게 된다.

위 그림에서 어댑터에 해당하는 SearchServiceTolrAdapter 클래스는 TolrClient를 SearchService 인터페이스에 맞춰 주는 책임을 갖는다. SearchServiceTolrAdapter 클래스의 search() 메서드는 아래의 코드처럼 TolrClient 객체를 실행하고 그 결과를 SearchService 인터페이스에 맞는 리턴 타입으로 변환해 준다. (상속을 이용해서 어댑터를 구현하는 경우, SearchServiceTolrAdapter 클래스의 search() 메서드는 상위 클래스인 TolrClient에 정의된 메서드를 호출하는 방식으로 코드를 작성하게 된다)

public class SearchServiceTolrAdapter implements SearchService {
    private TolrClient tolrClient = new TolrClient();
    
    public SearchResult search(String keyword) {
        // keyword를 tolrClient가 요구하는 형식으로 변환
        TolrQuery tolrQuery = new TolrQuery(keyword);
        //TolrClient 기능 실행
        QueryResponse response = tolrClient.query(tolrQuery);
        //TolrClioent의 결과를 SearchResult로 변환
        SearchResult result = convertToResult(response);
        return result;
    }
    
    private SearchResult convertToResult(QueryResponse response) {
        List<TolrDocument> tolrDocs = response.getDocumentList().getDocuments();
        List<SearchDocument> docs = new ArrayList<SearchDocument>();
        for(TolrDocument tolrDoc : tolrDocs) {
            docs.add(new SearchDocument(tolrDoc.getId(), ...);
        }
        return new SearchResult(docs);
    }
}

 추가적으로 자바는 클래스 단일 상속만을 지원하기 때문에, 클라이언트가 사용하는 SearchService가 인터페이스가 아닌 일부 구현이 포함된 추상 클래스라면, 어댑터 구현에 제약을 받는다. 

 

참고 영상: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/lecture/3173

 

자바 디자인 패턴의 이해 - Gof Design Pattern - 인프런

자바 디자인 패턴 이해하기 강좌 입니다. 여러가지 디자인 패턴들을 알아보며 디자인 패턴에 대한 이해도를 높이도록 도와줍니다. Gof Design Pattern을 자바 언어로 설명한 강의. 의미 있고 쉬운 예제를 준비하려고 노력했습니다. 중급 프로그래밍 언어 Java MVC 온라인 강의 자바 디자인 패턴

www.inflearn.com

참고 서적: 개발자가 반드시 정복해야 할 객체지향과 디자인 패턴

 

객체 지향과 디자인 패턴

객체 지향 안내서. 객체, 책임, 의존, 캡슐화 등 객체 지향의 주요 개념들을 쉬운 예제와 그림을 통해 이해하기 쉽게 설명한다.

www.yes24.com

 

728x90

'디자인 패턴' 카테고리의 다른 글

전략 패턴 (Strategy Pattern)  (0) 2020.10.02
3. 브릿지 패턴 (Bridge Pattern)  (0) 2020.04.25
1. 전략(Strategy) 패턴  (0) 2020.04.18