Goal
- 어댑터 패턴이란 무엇인지 알아보고 이해한다
- 어댑터 패턴을 사용한 코드를 이해한다
- 객체 어댑터와 클래스 어댑터를 이해한다
어댑터 패턴 (Adapter Pattern)
특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환한다. 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있다. => 어댑터는 한 객체의 인터페이스를 구현하고 다른 객체를 매핑한다.
언제 어댑터 패턴을 사용해야 할까?
새로운 클래스의 인터페이스가 기존 코드를 만들 때 사용했던 인터페이스와 다를 때 사용한다.
적용 예시
기존의 코드 Duck 인터페이스와 그를 확장한 MaralldDuck가 있다고 하자
public interface Duck {
public void quack();
public void fly();
}
public class MaralldDuck implements Duck{
@Override
public void quack() {
System.out.println("quack");
}
@Override
public void fly() {
System.out.println("im flying");
}
}
여기서 새로운 Turkey가 등장하였고, 그를 구현한 WildTurkey가 있다
public interface Turkey {
public void gobble();
public void fly();
}
public class WildTurkey implements Turkey{
@Override
public void gobble() {
System.out.println("gobble gobble");
}
@Override
public void fly() {
System.out.println("im flying a short distance");
}
}
*****
이때, Duck 객체가 모자라서 Turkey객체를 대신 사용해야 한다면?
인터페이스가 다르기에 Turkey 객체를 바로 사용할 수 없다
그 때 클라이언트에서 원하는 인터페이스인 TurkeyAdapter를 만든다
public class TurkeyAdapter implements Duck{ // 우선 적응시킬 형식의인터페이스를 구현
Turkey turkey;
public TurkeyAdapter(Turkey turkey) { // 기존 형식 객체의 레퍼런스가 필요. 여기서는 생성자에서 레퍼런스를 받아옴
this.turkey = turkey;
}
@Override
public void quack() { // 인터페이스에 들어있는 메소드 모두구현
turkey.gobble();
}
@Override
public void fly() {
// 칠면조는 멀리 날지 못하므로 다섯 번 날아서 오리처럼 긴 거리를 날게 한다
for(int i=0; i<5; i++) {
turkey.fly();
}
}
}
public class Driver {
public static void main(String[] args){
// 오리 생성
MaralldDuck duck = new MaralldDuck();
// 칠면조 생성
WildTurkey turkey = new WildTurkey();
// Turkey 객체를 TurkeyAdapter로 감싸서 Duck객체처럼 보이도록 함
Duck turkeyAdapter = new TurkeyAdapter(turkey);
// 칠면조 테스트
System.out.println("the turkey says");
turkey.gobble();
turkey.fly();
// 오리 테스트
System.out.println("the duck says");
testDcuk(duck);
// 칠면조 어댑터 테스트
System.out.println("the turkey adapter says");
testDcuk(turkeyAdapter);
}
private static void testDcuk(Duck duck) {
// Duck 객체를 받아 각 메소드 호출
duck.quack();
duck.fly();
}
}
결과
the turkey says
gobble gobble
im flying a short distance
the duck says
quack
im flying
the turkey adapter says
gobble gobble
im flying a short distance
im flying a short distance
im flying a short distance
im flying a short distance
im flying a short distance
장점
- 호환되지 않는 인터페이스를 사용하는 클라이언트를 그대로 활용가능
- 클라이언트와 구현된 인터페이스 분리가능 => SRP 단일 책임 원칙
- 변경 내역이 어댑터에 캡슐화되어 추후 인터페이스가 변경되어도 클라이언트를 바꿀 필요가 없음 => OCP 개방폐쇄 원칙
객체 어댑터와 클래스 어댑터
어댑터에는 두가지 종류가 있고, 하나는 객체 어댑터, 다른 하나는 클래스 어댑터이다.
위에서는 객체 어댑터를 다뤘고, 자바에서는 다중상속이 불가능하기 때문에 클래스 어댑터 패턴을 사용하지 않는다.
객체 어댑터는 어댑티를 적응시킬 때 구성을 사용하고 클래스 어댑터는 상속(어댑티와 타킷클래스의 서브클래스로)을 사용한다.
정리
어댑터 패턴은 합성, 즉 객체를 속성으로 만들어서 참조하는 디자인 패턴으로 호출당하는 메서드 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴이다
참고
헤드퍼스드 디자인 패턴
스프링 입문을 위한 자바 객체지향의 원리와 이해
'JAVA > 디자인 패턴' 카테고리의 다른 글
[Proxy Pattern] 프록시 패턴 - 가상 프록시 (0) | 2023.07.03 |
---|---|
[Proxy Pattern] 프록시 패턴 - 원격 프록시 (0) | 2023.07.03 |
[Proxy Pattern] 프록시 패턴이란? (0) | 2023.07.03 |
[Design Pattern] 디자인 패턴이란? (0) | 2023.06.28 |
[Singleton Pattern] 싱글톤 패턴 (0) | 2023.06.27 |