Table of Contents
[GoF 디자인 패턴] 적응자(Adapter) 패턴
구조(structural) 패턴 중 하나로, 호환되지 않는 인터페이스를 가진 두 개의 클래스를 함께 사용할 수 있는 디자인 패턴이다.
기존의 클래스와 새로운 인터페이스 간의 호환성을 제공하기 위해 중간에 어댑터(Adapter) 클래스를 두어 기존 클래스의 인터페이스를 새로운 인터페이스로 변환할 수 있다.
![Object Adapter](/images/gof-design-pattern-adapter/1.png)
Object Adapter
![Class Adapter](/images/gof-design-pattern-adapter/2.png)
Class Adapter
적응자 패턴 구성요소
- Target : Client가 사용할 새로운 인터페이스
- Adaptee : 기존에 존재하는 새로운 인터페이스를 구현하지 않는 클래스
- Adapter : Target 인터페이스를 구현하면서 Adaptee 인스턴스를 감싸 새로운 인터페이스에 맞게 변환해주는 클래스
구현 예제
적응자 패턴은 Class Adapter, Object Adapter 두가지로 나뉜다. Class Adapter는 상속을 통해 구현되고, Object Adapter는 기존 클래스 객체(Adaptee) 를 다른 객체 내부에 포함시켜 새로운 인터페이스로 구현하는 방식이다.
우선 Class Adapter를 구현한 예제이다.
기존에 존재하는 Adaptee 클래스를 만들어준다.
1public class GoogleAdaptee {
2 public void translateByGoogle() {
3 System.out.println("구글 번역기를 사용합니다.");
4 }
5}
이 GoogleAdaptee 클래스는 수정이 불가능한 상황이고 새로운 Target 인터페이스에서 GoogleAdaptee 기능을 사용하고 싶다.
새로운 인터페이스인 Target 인터페이스를 만들어준다.
1public interface PapagoTranslation {
2 void translateByPapago();
3}
Adapter가 구현해야 할 Target 역할을 한다.
Adapter 클래스에 Adaptee를 사용하는 새로운 인터페이스를 구현한다.
1public class PapagoAdapter extends GoogleAdaptee implements PapagoTranslation {
2
3 @Override
4 public void translateByPapago() {
5 System.out.println("파파고 번역기에서 구글 번역 기능을 사용합니다.");
6 this.translateByGoogle();
7 }
8}
Adaptee 와 Target을 연결해주는 Adapter의 역할을 한다. PapagoAdapter 클래스는 GoogleAdaptee 클래스를 상속받기 때문에 Adaptee 객체를 가지고 있고, PapagoTranslation 인터페이스를 구현하므로 Target 인터페이스의 역할을 수행할 수 있다.
→ “호환되지 않는 두 개의 클래스를 함께 사용할 수 있게 되어 유연성이 증가한다.”
다음은 Object Adapter를 구현한 예제이다.
Class Adapter 예제와 똑같은 Adaptee 클래스와 Targer 인터페이스를 만들어주었다.
1public class GoogleAdaptee {
2 public void translateByGoogle() {
3 System.out.println("구글 번역기를 사용합니다.");
4 }
5}
6public interface PapagoTranslation {
7 void translateByPapago();
8}
GoogleAdaptee 클래스는 기존에 존재하는 클래스이고, PapagoTranslation 인터페이스는 Client가 새로 구현하려는 인터페이스이다.
Adapter 클래스를 만들어준다.
1public class PapagoAdapter implements PapagoTranslation {
2 private final GoogleAdaptee googleAdaptee;
3
4 public PapagoAdapter(GoogleAdaptee googleAdaptee) {
5 this.googleAdaptee = googleAdaptee;
6 }
7 @Override
8 public void translateByPapago() {
9 System.out.println("파파고 번역기에서 구글 번역 기능을 사용합니다.");
10 googleAdaptee.translateByGoogle();
11 }
12}
Class Adapter과 다르게 Adaptee 객체를 인수로 받아서 Target 인터페이스를 구현한다.
Class Adapter와 Object Adapter에 대해 요약하자면 다음과 같다.
- Class Adapter
- 장점 : Adaptee를 오버라이드 할 수 있다. Adaptee 객체를 만들지 않아도 된다.
- 단점 : 다중 상속이 지원되는 언어에서만 사용할 수 있다. 특정 Adaptee 클래스만 적용할 수 있다.
- Object Adapter
- 장점 : 객체 합성을 사용하기 때문에 유연하다.
- 단점 : Adaptee 객체를 만들어야 한다.
적응자 패턴 고려사항
적응자 패턴은 호환되지 않는 인터페이스를 두 개의 클래스와 함께 사용할 경우 유용하게 사용할 수 있다. 기존 코드를 재사용하거나 수정을 최소화할 경우 적응자 패턴을 사용하는 것은 좋은 방법이지만, 클래스 간의 호환성 문제가 없거나 클래스 간의 차이가 너무 크고 여러 개의 클래스를 함께 사용해야 할 때는 코드가 복잡해 질 수 있다.
적응자 패턴 사용 시 장점
- 기존 코드의 재사용성을 높일 수 있다.
- 새로운 인터페이스를 추가할 때, 기존 코드 수정을 최소화할 수 있다.
적응자 패턴 사용 시 단점
- Object Adapter 패턴을 사용할 경우 추가적인 객체 생성으로 인해 오버헤드가 발생할 수 있다.
- Class Adapter 패턴을 사용할 경우 이미 다른 클래스를 상속하고 있는 경우 적응자 패턴을 만들 수 없다는 한계가 있다.