티스토리 뷰

1. 어댑터 패턴?

한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.

어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

 

구조

Target

- Client가 사용할 특정 도메인에 한정되는 인터페이스

 

Client

- Target와 연관된 객체들을 사용한다.

 

Adaptee

- 변환이 필요한 인터페이스

 

Adapter

- Adaptee 인터페이스를 Target 인터페이스의 규격에 맞춘다.

 

간단하게 말하자면: Adaptee를 Target의 형식에 끼워 맞추는 역할을 Adapter가 담당하는 것이다.

- 기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴

- 클라이언트가 사용하는 인터페이스를 따르지 않는 기존 코드를 재사용할 수 있게 해준다.

 

2. 동기

장점:

1) 기존 코드를 변경하지 않고 원하는 인터페이스 구현체를 만들어 재사용할 수 있다.

2) 기존 코드가 하던 일과 특정 인터페이스 구현체로 변환하는 작업을 각기 다른 클래스로 분리하여 관리할 수 있다.

 

단점:

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

 

3. 구현

구현 포인트:

1) Adapter의 역할은 어디까지이어야 하는가?

- 간단한 인터페이스 변환 역할인가? ex. 함수 이름만 변하는 케이스

- 내부적으로 서로 완전히 다른 기능으로 변환 시키는가?

- Adapter가 얼만큼 책임을 맡아야 하는가는 Target 과 Adaptee 끼리 얼마나 닮아있느냐에 따라 달라진다.

 

2) Pluggable Adapter

3) Parameterized Adapter

 

샘플코드:

public class LoginHandler {

    UserDetailsService userDetailsService;

    public LoginHandler(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public String login(String username, String password) {
        UserDetails userDetails = userDetailsService.loadUser(username);
        if (userDetails.getPassword().equals(password)) {
            return userDetails.getUsername();
        } else {
            throw new IllegalArgumentException();
        }
    }
}


public interface UserDetails {

    String getUsername();

    String getPassword();

}

public interface UserDetailsService {

    UserDetails loadUser(String username);

}
public class Account {

    private String name;

    private String password;

    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

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) {

    }

}

 

public class AccountUserDetails implements UserDetails {

    private Account account;

    public AccountUserDetails(Account account) {
        this.account = account;
    }

    @Override
    public String getUsername() {
        return account.getName();
    }

    @Override
    public String getPassword() {
        return account.getPassword();
    }
}

public class AccountUserDetailsService implements UserDetailsService {

    private AccountService accountService;

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

    @Override
    public UserDetails loadUser(String username) {
        return new AccountUserDetails(accountService.findAccountByUsername(username));
    }
}

...

    public static void main(String[] args) {
        AccountService accountService = new AccountService();
        UserDetailsService userDetailsService = new AccountUserDetailsService(accountService);
        LoginHandler loginHandler = new LoginHandler(userDetailsService);
        String login = loginHandler.login("user", "user");
        System.out.println(login);
    }


...

 

4. 개인적인 포인트

- java Collections - Arrays  - Enumeration 

 

//collections
List<Strings> strings = Arrays.asList("a","b","c");
Enumeration<String> enums = Collections.enumeration(strings);
ArrayList<String> list = Collections.list(enumeration);