[디자인패턴] 4. Adapter

문정준's avatar
Jul 22, 2025
[디자인패턴] 4. Adapter

Adapter (어댑터)

  • Proxy와 별개로 해당 객체의 다른 책임을 대신 받아서 처리할 수 있는 객체
  • 기존 시스템의 구조를 해치지 않으면서 새 클래스를 기존 시스템에 넣을 수 있도록 변환
 
notion image
notion image
 

어댑터는 책임을 위임 받는 역할이 아님

  • 어댑터는 새로운 기능이 추가되어야 할 때 기존 시스템에 맞춰서 끼우기 위한 도구
  • 프록시처럼 역할을 위임받는 역할이 아니지만 SRP, DIP를 수행하기 위해 비슷한 역할을 수행할 수 있음
 
 

Q1. 동물의 객체 이름이 name이 아닌 fullName으로 왔다면?

  • 동물 객체는 name을 이용한 getName을 사용
  • OuterTiger는 fullName을 사용하므로 메소드를 맞추어줘야 하는데, 이를 직접 건드리면 안됨
    • 다른 곳에서 메소드를 사용 중일 경우 모든 곳을 손봐야 함
// 외부 요소 public class OuterTiger { private String fullName = "호랑이"; public String getFullName() { return fullName; } }

A : 기존 동물 객체에서 사용하던 name으로 맞춰주는 어댑터가 필요함

// Adapter : Animal 객체에 OuterTiger를 맞추기 위한 수단 public class TigerAdapter extends Animal{ // DI private OuterTiger outerTiger; public TigerAdapter(OuterTiger outerTiger) { this.outerTiger = outerTiger; } // extends @Override String getName() { return outerTiger.getFullName(); } } public class App { public static void main(String[] args) { Mouse m1 = new Mouse(); Doorman d1 = new Doorman(); Cat c1 = new Cat(); // 기존 코드는 놔두면서 어댑터만 추가함 TigerAdapter ta = new TigerAdapter(new OuterTiger()); d1.쫓아내(m1); d1.쫓아내(c1); d1.쫓아내(ta); } }
 

Q2. 로그인 방법을 하나 더 추가할 건데, 코드를 건드리지 않으려면?

  • 카카오, 구글 로그인이 구현되어 있음
  • 페이스북 로그인을 추가할 건데, 로그인 하면 uid, uname을 리턴함
 

A :

내가 푼 답
  • 로그인 하는 provider에 따라 로그인을 구분해야 하는데, AuthAdapter에서 이를 처리하도록 수정
  • Authenticator의 책임이 너무 많으므로 추상화
  • provider → loginadapter → authadapter → kakao, google, facebook으로 분할
Feedback :
  • provider에 따라 로그인을 구분할 때는 해당하는 provider를 선택해주는 factory가 필요
  • factory가 있으면 loginadapter, authadapter가 필요 없어짐
  • 카카오, 구글, 페이스북 프로필 정보를 가져오는 UserProfile 객체가 필요
    • 추상화로 구성하여 단일 객체에만 의존하도록 수정
    • 이때, 카카오, 구글, 페이스북 프로필이 전부 UserProfile에 상속되어 있어야 함
  • 카카오, 구글, 페이스북 로그인의 책임을 각자 상속받는 객체들이 필요
    • Authentication은 내부 구조는 필요 없음 (추상 클래스만)
풀이
  • App.java
// FacebookProfile -> uId, uName (이게 추가될때 기존 코드를 손되지 않을 수 있게 하는게 목표) public class App { static void mainPage(UserProfile profile) { System.out.println("로그인 하신 아이디는 " + profile.getUsername() + " 입니다."); } public static void main(String[] args) { Scanner sc = new Scanner(System.in); String provider = sc.nextLine(); // 객체 생성 전담 클래스를 만들어서 처리해주면 좋다. Authentication authentication; if (provider.equals("google")) { authentication = new GoogleAuthentication(); } else if (provider.equals("kakao")) { authentication = new KakaoAuthentication(); } else if (provider.equals("facebook")) { authentication = new FacebookAuthentication(); } else { System.out.println("지원하지 않는 Provider 입니다."); return; } UserProfile userProfile = authentication.login(); mainPage(userProfile); } }
  • Authentication.java
public abstract class Authentication { public abstract UserProfile login(); }
  • UserProfile.java
// 추상화 public class UserProfile { public int getId() { return 0; } public String getUsername() { return "정원"; } }
  • FacebookAuthentication.java
// SRP를 지키기 위해 public class FacebookAuthentication extends Authentication { public UserProfile login() { System.out.println("페이스북 로그인 완료"); return new FacebookProfile(999, "love"); } }
  • GoogleAuthentication.java
// SRP를 지키기 위해 public class GoogleAuthentication extends Authentication { public UserProfile login() { System.out.println("구글 로그인 완료"); return new GoogleProfile(500, "cos"); } }
  • KakaoAuthentication.java
// SRP를 지키기 위해 public class KakaoAuthentication extends Authentication { public UserProfile login() { System.out.println("카카오 로그인 완료"); return new KakaoProfile(1, "ssar"); } }
  • FacebookProfile.java
public class FacebookProfile extends UserProfile { private int uId; private String uName; public FacebookProfile(int uId, String uName) { this.uId = uId; this.uName = uName; } public int getId() { return uId; } public String getUsername() { return uName; } }
  • GoogleProfile.java
public class GoogleProfile extends UserProfile { private int id; private String username; public GoogleProfile(int id, String username) { this.id = id; this.username = username; } public int getId() { return id; } public String getUsername() { return username; } }
  • KakaoProfile.java
public class KakaoProfile extends UserProfile { private int sub; private String name; public KakaoProfile(int sub, String name) { this.sub = sub; this.name = name; } public int getId() { return sub; } public String getUsername() { return name; } }
 

Q3. 미연결된 네이버 로그인도 연결하려면?

A :

  • 네이버 프로필에서 id와 mainName을 반환 (UserProfile의 getId, getUsername을 사용할 수 없음)
    • 네이버 프로필 어댑터 생성 (id, mainName을 받아 getId, getUsername 구현)
  • 네이버 로그인 인증 구현 (네이버 프로필 어댑터 타입 반환)
  • main에서 인증 코드 삽입
 
Share article

sxias