코드의 변경 없이, 기존 구현체를 클라이언트가 사용하는 인터페이스의 구현체로 변환시켜주는 패턴
사용 목적
클라이언트가 사용하는 인터페이스를 따르지 않던 기존 구현체를 그에 맞게 변환하여, 재사용 가능하도록 하기 위함
또한, 이를 기존 구현체 코드의 변경 없이 수행하기 위함
2 + 3부 : 패턴 적용 및 장,단점
문제 상황
클라이언트( LoginHandler ) 는 두 인터페이스(UserDetails, UserDetailsService ) 만 사용하고, 기존의 구현체(Account, AccountService ) 는 인터페이스를 따르지 않으므로 사용자가 접근할 수 없음
따라서, 기존 구현체가 타겟 인터페이스를 따르도록 변환해야 하는 상황
어댑터 패턴을 적용하지 않고 변환
기존 구현체를 타겟 인터페이스의 구현체로 직접 변환
public class Account implements UserDetails{
@Override
public String getUsername() {
}
}
public class AccountService implements UserDetailsService {
@Override
public UserDetails loadUser(String username) {
return null;
}
}
장점
어댑터 클래스를 추가하지 않아도 됨
단점
기존 구현체의 코드를 변경해야 함 => Open-Closed 원칙 위배
기존 구현체의 책임에 인터페이스 구현체로써의 책임이 추가 => 단일 책임 원칙 위배
어댑터 패턴을 적용하여 변환
타겟 인터페이스를 따르는 구현체를 기존 인스턴스로 직접 설정하지 않고, 어댑터를 사용함
어댑터(타겟 인터페이스의 구현체)는 기존 인스턴스를 주입받고, 이를 활용하여 인터페이스 메소드를 구현함으로써 기존 인스터스가 인터페이스의 구현체로 변환된것 처럼 동작하게 한다
장점
기존 구현체의 코드를 변경하지 않고도 재사용 가능하게 함 => Open-Closed 원칙 달성
타겟 인터페이스 구현체로의 변환 책임을 분리 => 단일 책임 원칙 달성
단점
어댑터 클래스의 추가로 복잡도 증가
결론
경우에 따라 기존 구현체가 인터페이스를 따르도록 직접 수정하는 것도 좋은 선택이 될 수 있음
4부 : 자바와 스프링에서 찾아보는 패턴
Adapter 가 Adaptee 를 Target Interface 로 변환하는 모든 형태
In Java
// collections
List<String> strings = Arrays.asList("a", "b", "c");
Enumeration<String> enumeration = Collections.enumeration(strings);
ArrayList<String> list = Collections.list(enumeration);
// io
try(InputStream is = new FileInputStream("input.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr)) {
while(reader.ready()) {
System.out.println(reader.readLine());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
1부 : 패턴 소개
어댑터(Adapter) 패턴이란?
사용 목적
2 + 3부 : 패턴 적용 및 장,단점
문제 상황
어댑터 패턴을 적용하지 않고 변환
장점
단점
어댑터 패턴을 적용하여 변환
장점
단점
결론
4부 : 자바와 스프링에서 찾아보는 패턴
In Java
In Spring