Ian's Archive 🏃🏻

Profile

Ian

Ian's Archive

Developer / React, SpringBoot ...

📍 Korea
Github Profile →
Categories
All PostsAlgorithm19Book1C1CI/CD2Cloud3DB1DesignPattern9ELK4Engineering1Front3Gatsby2Git2IDE1JAVA7JPA5Java1Linux8Nginx1PHP2Python1React9Security4SpatialData1Spring26
thumbnail

어댑터 패턴 정리

DesignPattern
2025.11.03.

1. 어댑터 패턴

  • 기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴
  • 서로 다른 인터페이스를 구현하는 코드들을, 서로 상호 호환되도록 구조를 변경해주는 어댑터를 제공하는 패턴
  • 즉, 클라이언트가 사용하는 인터페이스를 따르지 않는 기존 코드를 재사용 가능하도록 설계

Tip!

  • 어댑터가 Legacy 인터페이스를 감싸서 새로운 인터페이스로 변환하기 때문에 Wrapper 패턴이라고도 불린다.

1

2

2. 어댑터 패턴 구현 방법

  • 제공되는 클래스를 건드릴 수 없는 경우(서드파티에서 제공하는 클래스, 엄청난 레거시 코드) -> 내가 작성한 코드로 융합할 때 사용
  • 기존의 코드는 건드리지 않고, 코드(Adaptee)와 융합한 클래스(Adapter)를 구현
  1. 써드 파티 라이브러리가 있다고 가정
복사
@AllArgsConstructor
public class LoginHandler {

    UserDetailsService userDetailsService;

    public String login(String username, String password) {

        UserDetails userDetails = userDetailsService.loadUser(username);

        if (userDetails.getPassword().equals(password)) {
            return userDetails.getUserName();
        }

        throw new IllegalArgumentException();
    }

}

public interface UserDetailsService {

    UserDetails loadUser(String userName);
}


public interface UserDetails {

    String getUserName();
    String getPassword();
}
  1. 써드파티를 사용해야 하는 Adaptee 역할을 하는 코드가 있다고 가정
복사
//Account 와 AccountService 는 해당 app 단위에서만 사용하는 일정의 adaptee
public class AccountService {

    public Account findAccountByUsername(String username) {
        Account account = new Account();
        account.setName(username);
        account.setPassword(username);
        account.setEmail(username);

        return account;
    }

    public void createNewAccount(Account account) {

    }

    public void updateAccount(Account account) {

    }
}

@Getter
@Setter
public class Account {

    private String name;
    private String password;
    private String email;
}
  1. Adaptee가 변경할 수 없는 제공받는 코드를 사용할 수 있도록 Adapter를 구현해서 기존 코드를 재사용
복사
public class AccountUserDetailsService implements UserDetailsService {

    AccountService accountService;

    public AccountUserDetailsService(AccountService accountService) {
        this.accountService = accountService;
    }

    @Override
    public UserDetails loadUser(String userName) {
        Account account = accountService.findAccountByUsername(userName);

        return new AccountUserDetails(account);
    }
};

public class AccountUserDetails implements UserDetails {

    private Account account;

    public AccountUserDetails(Account account) {
        this.account = account;
        this.account = account;
    }
    @Override
    public String getUserName() {
        return this.account.getName();
    }

    @Override
    public String getPassword() {
        return this.account.getPassword();
    }
}
  1. 클라이언트 코드
  • 실 사용하는 클라이언트 코드에서 어뎁터 class를 사용해 외부 라이브러리를 사용하면서 기존 코드도 재사용 하는 구조가 되어진다
  • 또한 새로운 Adaptee를 사용한다고 하더라도 기존 코드가 변경되지 않고 Adapter를 새롭게 생성하여 확장이 가능한 구조가 되어진다.
복사
// 직접 코드변경이 가능하면 Account, AccountService, 어뎁티를 직접 수정
public class App {
    public static void main(String[] args) {
        AccountService accountService = new AccountService();
        UserDetailsService userDetailsService = new AccountUserDetailsService(accountService);
        LoginHandler loginHandler = new LoginHandler(userDetailsService);

        String login = loginHandler.login("hmin", "hmin");
        System.out.println("login = " + login);
    }
}

3. 어댑터 패턴 장점 및 단점

장점

  • 기존 코드를 변경하지 않고 원하는 인터페이스 구현체를 만들어 재사용 (OCP)
  • 기존 코드가 하던 일, 특정 인터페이스 구현체로 변환하는 작업을 각기 다른 클래스로 분리하여 관리 (SRP)

단점

  • 새 클래스가 생겨 복잡도가 증가할 수 있음
  • 경우에 따라서 기존 코드가 해당 인터페이스를 구현하도록 수정하는 것이 좋은 선택일 수 있다.

기존의 클래스를 새로운 인터페이스에 맞게 개조하고 싶을때, 우리는 기존 클래스의 소스를 바꾸어 수정한다.
하지만, 이런식으로 개발을 진행하면 이미 동작 테스트가 끝난 기존의 클래스를 다시 한번 테스트해야 한다.
이러한 관점에서 어댑터 패턴은 기존의 클래스를 수정하지 않고, 새로운 인터페이스에 맞게 호환 작업을 중계해주는 것이다.

4. 실무에서 찾아보는 어댑터 패턴

  • java.util.Arrays 의 asList()
  • java.util.Collections 의 list()
  • java.util.Collections 의 enumeration()
  • java.io.InputStreamReader(InputStream) (returns a Reader)
  • java.io.OutputStreamWriter(OutputStream) (returns a Writer)
  • javax.xml.bind.annotation.adapters.XmlAdapter 의 marshal() and unmarshal()
  • Spring Security

Reference

코딩으로 학습하는 GoF의 디자인 패턴 - 백기선
어댑터(Adaptor) 패턴 - 완벽 마스터하기 - Inpa

Previous Post
프로토타입 패턴 정리
Next Post
복합체(Composite) 패턴 정리
Thank You for Visiting My Blog, I hope you have an amazing day 😆
© 2023 Ian, Powered By Gatsby.