어댑터 패턴

Adapter pattern

소프트웨어 엔지니어링에서 어댑터 패턴은 기존 클래스인터페이스를 다른 [1]인터페이스로 사용할 수 있도록 하는 소프트웨어 설계 패턴(일명 래퍼라고도 함)입니다.소스 코드를 수정하지 않고 기존 클래스가 다른 클래스와 함께 작동하도록 하는 데 자주 사용됩니다.

예를 들어 XML 문서의 Document Object Model 인터페이스를 표시할 수 있는 트리 구조로 변환하는 어댑터가 있습니다.

개요

어댑터[2] 설계 패턴은 23개의 잘 알려진 설계 패턴 중 하나로 유연하고 재사용 가능한 객체 지향 소프트웨어, 즉 구현, 변경, 테스트 및 재사용이 용이한 객체를 설계하기 위해 반복되는 설계 문제를 해결하는 방법을 설명합니다.

어댑터 설계 패턴은 다음과 [3]같은 문제를 해결합니다.

  • 클라이언트에 필요한 인터페이스가 없는 클래스를 재사용하려면 어떻게 해야 합니까?
  • 호환되지 않는 인터페이스를 가진 클래스는 어떻게 함께 작동합니까?
  • 클래스에 대체 인터페이스를 제공하려면 어떻게 해야 합니까?

(기존의) 클래스는, 그 인터페이스가 클라이언트에 필요한 인터페이스에 준거하고 있지 않기 때문에, 재이용할 수 없습니다.

어댑터 설계 패턴은 이러한 문제를 해결하는 방법을 설명합니다.

  • 별도 정의adapter클래스의 (비활성) 인터페이스를 변환하는 클래스(adaptee를 다른 인터페이스(target클라이언트는 필요합니다.
  • 를 통해 작업합니다.adapter필요한 인터페이스가 없는 (비활성화) 클래스로 동작합니다.

이 패턴의 핵심 아이디어는 별도의 방법을 통해 작업하는 것입니다.adapter(기존 클래스 제외)의 인터페이스를 변경하지 않고 조정합니다.

클라이언트는, 고객이 사용하는 네트워크와target직접 또는 경유로 분류하는adapter를 가지고 있지 않은 클래스와 함께target인터페이스입니다.

다음 UML 클래스 다이어그램도 참조하십시오.

정의.

어댑터는 호환되지 않는 두 개의 인터페이스를 함께 사용할 수 있도록 합니다.이것이 어댑터의 실제 정의입니다.인터페이스가 호환되지 않을 수 있지만 내부 기능은 필요에 따라 적합해야 합니다.어댑터 설계 패턴에서는 1개의 클래스의 인터페이스를 클라이언트가 기대하는 인터페이스로 변환함으로써 호환되지 않는 클래스가 함께 동작할 수 있습니다.

사용.

어댑터는 래퍼가 특정 인터페이스를 존중하고 다형 동작을 지원해야 할 때 사용할 수 있습니다.또는 데코레이터는 런타임에 인터페이스의 동작을 추가 또는 변경할 수 있도록 하고, 기초 물체에 대한 보다 쉽고 간단한 인터페이스를 [4]원할 때 파사드를 사용한다.

양식 의도
어댑터 또는 래퍼 클라이언트가 기대하는 것과 일치하도록 인터페이스를 다른 인터페이스로 변환합니다.
데코레이터 원래 코드를 래핑하여 인터페이스에 동적으로 책임 추가
위임 "상속보다 구성" 지원
전면 심플한 인터페이스 제공

구조.

UML 클래스 다이어그램

어댑터 설계 [5]패턴의 UML 클래스 다이어그램 예시.

위의 UML 클래스 다이어그램에서는client를 필요로 하는 클래스target인터페이스는, 를 재이용할 수 없습니다.adaptee인터페이스가 에 준거하고 있지 않기 때문에, 직접 클래스 합니다.target인터페이스입니다.대신,client를 통해 동작합니다.adapter를 실장하는target관점에서 접하다adaptee:

  • object adapterway는 를 구현합니다.target에 위임함으로써 인터페이스adaptee실행 시 오브젝트(adaptee.specificOperation()).
  • class adapterway는 를 구현합니다.target에서 상속함으로써 인터페이스adapteeclass at 컴파일 시)specificOperation()).

오브젝트 어댑터 패턴

이 어댑터 패턴에서는 어댑터에 랩된 클래스의 인스턴스가 포함되어 있습니다.이 경우 어댑터는 랩된 객체의 인스턴스에 콜을 발신합니다.

UML로 표현되는 객체어댑터 패턴
LePUS3로 표현되는 객체어댑터 패턴

클래스 어댑터 패턴

이 어댑터 패턴에서는 예상되는 인터페이스와 기존 인터페이스 모두를 구현 또는 상속하는 여러 폴리모픽인터페이스를 사용합니다.일반적으로 예상되는 인터페이스는 순수 인터페이스 클래스로 작성됩니다.특히 Java 등의 언어(JDK 1.8 이전)에서는 클래스[1]다중 상속을 지원하지 않습니다.

UML로 표시되는 클래스 어댑터 패턴.
LePUS3로 표현되는 클래스 어댑터 패턴

새로운 형태의 런타임 어댑터 패턴

컴파일 시간 솔루션의 동기 부여

그것은 에 바람직하다.classA공급하다classB어떤 데이터를 가지고 있다고 가정해 봅시다.String데이터. 컴파일 시간 솔루션은 다음과 같습니다.

클래스 B.set String Data(클래스 A.getStringData()); 

단, 문자열 데이터의 형식을 변경해야 한다고 가정합니다.컴파일 시간 솔루션은 상속을 사용하는 것입니다.

일반의 학급 형식 1 클래스a 확장 클래스 A {     @오버라이드     일반의 스트링 getStringData() {         돌아가다 포맷(문자열());     } } 

또한 런타임에 공장 패턴을 사용하여 올바른 "포맷" 개체를 생성할 수도 있습니다.

런타임 어댑터 솔루션

「어댑터」를 사용한 솔루션은, 다음과 같이 진행됩니다.

  1. 중간 '프로바이더' 인터페이스를 정의하고 데이터의 소스를 감싸는 프로바이더인터페이스의 실장을 작성합니다.ClassA이 예에서는 적절한 형식의 데이터를 출력합니다.
    일반의 인터페이스 String Provider(스트링 프로바이더) {     일반의 스트링 getStringData(); }  일반의 학급 클래스 AFOrmat1 용구 String Provider(스트링 프로바이더) {     사적인 클래스 A 클래스 A = 무효;      일반의 클래스 AFOrmat1(최종 클래스 A a) {         클래스 A = a;     }      일반의 스트링 getStringData() {         돌아가다 포맷(클래스 A.getStringData());     }      사적인 스트링 포맷(최종 스트링 source Value) {         // 소스 문자열을 필요한 형식으로 조작합니다.         // 소스 객체의 데이터를 필요로 하는 객체별         돌아가다 source Value.다듬다();     } } 
  2. 프로바이더의 특정 구현을 반환하는 어댑터 클래스를 작성합니다.
    일반의 학급 Class AFOrmat 1 어댑터 확장 어댑터 {     일반의 물건 적응하다(최종 물건 오브젝트) {         돌아가다 신규 클래스 AFOrmat1((클래스 A) 오브젝트);     } } 
  3. 등록하다adapter글로벌 레지스트리를 사용하여adapter런타임에 조회할 수 있습니다.
    어댑터 팩토리.get Instance(인스턴스().레지스터 어댑터(클래스 A.학급, Class AFOrmat 1 어댑터.학급, "format1"); 
  4. 코드에서는 데이터 전송을 원하는 경우ClassA로.ClassB, 쓰기:
    어댑터 어댑터 =     어댑터 팩토리.get Instance(인스턴스()         .get Adapter로.(클래스 A.학급, String Provider(스트링 프로바이더).학급, "format1"); String Provider(스트링 프로바이더) 프로바이더 = (String Provider(스트링 프로바이더)) 어댑터.적응하다(클래스 A); 스트링 스트링 = 프로바이더.getStringData(); 클래스 B.set String Data(스트링); 

    또는 보다 간결하게:

    클래스 B.set String Data(     ((String Provider(스트링 프로바이더))             어댑터 팩토리.get Instance(인스턴스()                 .get Adapter로.(클래스 A.학급, String Provider(스트링 프로바이더).학급, "format1")                 .적응하다(클래스 A))         .getStringData()); 
  5. 장점은 두 번째 형식으로 데이터를 전송해야 할 경우 다른 어댑터/공급자를 검색해야 한다는 것입니다.
    어댑터 어댑터 =     어댑터 팩토리.get Instance(인스턴스()         .get Adapter로.(클래스 A.학급, String Provider(스트링 프로바이더).학급, "format2"); 
  6. 그리고 데이터를 출력하고 싶은 경우ClassA예를 들어 이미지 데이터로서Class C:
    어댑터 어댑터 =     어댑터 팩토리.get Instance(인스턴스()         .get Adapter로.(클래스 A.학급, 이미지 프로바이더.학급, "format2"); 이미지 프로바이더 프로바이더 = (이미지 프로바이더) 어댑터.적응하다(클래스 A); 클래스 C.set 이미지(프로바이더.이미지 가져오기()); 
  7. 이와 같이 어댑터와 프로바이더를 사용하면 다음과 같은 방법으로 여러 개의 "보기"를 수행할 수 있습니다.ClassB그리고.ClassC안으로ClassA계층 구조를 바꾸지 않아도 됩니다.일반적으로 기존 개체 계층에 재구성할 수 있는 개체 간의 임의 데이터 흐름을 위한 메커니즘을 허용합니다.

어댑터 패턴 구현

어댑터 패턴을 구현할 때 클래스 이름을 적용할 수 있습니다.[ClassName]To[Interface]Adapter예를 들어 다음과 같습니다.DAOToProviderAdapteradaptee 클래스 변수를 매개 변수로 하는 컨스트럭터 메서드가 있어야 합니다.이 파라미터는 의 인스턴스 멤버에게 전달됩니다.[ClassName]To[Interface]AdapterclientMethod가 호출되면 어댑터의 필수 데이터에 액세스하여 원하는 출력을 생성하는 해당 데이터에 대한 작업을 수행할 수 있는 어댑터의 인스턴스에 액세스할 수 있습니다.

자바

인터페이스 ILightning Phone(전화기) {     무효 충전하다();     무효 useLightning(번개)(); }  인터페이스 IMicroUbPhone {     무효 충전하다();     무효 MicroUb 사용(); }  학급 Iphone 용구 ILightning Phone(전화기) {     사적인 부울 커넥터;      @오버라이드     일반의 무효 useLightning(번개)() {         커넥터 = 진실의;         시스템..나가..인쇄("번개 연결됨");     }      @오버라이드     일반의 무효 충전하다() {         한다면 (커넥터) {             시스템..나가..인쇄("재충전 시작");             시스템..나가..인쇄("재충전 완료");         } 또 다른 {             시스템..나가..인쇄("먼저 라이트닝 연결");         }     } }  학급 안드로이드 용구 IMicroUbPhone {     사적인 부울 커넥터;      @오버라이드     일반의 무효 MicroUb 사용() {         커넥터 = 진실의;         시스템..나가..인쇄("MicroUb 연결됨");     }      @오버라이드     일반의 무효 충전하다() {         한다면 (커넥터) {             시스템..나가..인쇄("재충전 시작");             시스템..나가..인쇄("재충전 완료");         } 또 다른 {             시스템..나가..인쇄("먼저 MicroUb 연결");         }     } } /* 소스 개체를 래핑하는 동안 대상 인터페이스를 노출합니다 */ 학급 LightningToMicroUb어댑터 용구 IMicroUbPhone {     사적인 최종 ILightning Phone(전화기) 라이트닝 폰;      일반의 LightningToMicroUb어댑터(ILightning Phone(전화기) 라이트닝 폰) {         이것..라이트닝 폰 = 라이트닝 폰;     }      @오버라이드     일반의 무효 MicroUb 사용() {         시스템..나가..인쇄("MicroUb 연결됨");         라이트닝 폰.useLightning(번개)();     }      @오버라이드     일반의 무효 충전하다() {         라이트닝 폰.충전하다();     } }  일반의 학급 어댑터 데모 {     정적인 무효 재충전 MicroUbPhone(IMicroUbPhone 전화) {         전화.MicroUb 사용();         전화.충전하다();     }      정적인 무효 재충전 Lightning Phone(ILightning Phone(전화기) 전화) {         전화.useLightning(번개)();         전화.충전하다();     }      일반의 정적인 무효 주된(스트링[] args) {         안드로이드 안드로이드 = 신규 안드로이드();         Iphone 아이폰 = 신규 Iphone();          시스템..나가..인쇄("MicroUb로 안드로이드 충전 중");         재충전 MicroUbPhone(안드로이드);          시스템..나가..인쇄('번개로 아이폰 충전');         재충전 Lightning Phone(아이폰);          시스템..나가..인쇄("MicroUb로 아이폰 충전 중");         재충전 MicroUbPhone(신규 LightningToMicroUb어댑터 (아이폰));     } } 

산출량

MicroUSB MicroUSB 연결 충전 시작 충전 완료 번개 연결 충전 완료 충전 완료 MicroUSB MicroUSB 연결 충전 완료 충전 완료 충전 완료

파이썬

""" 어댑터 패턴의 예. """ 부터 abc 수입품 ABC메타, 추상적 방법  미실장 = "이것을 구현해야 합니다."  충전 = ["충전 시작", "충전 완료"]  POWER_어댑터 = {'안드로이드': "MicroUSB", '아이폰': '번개'}  연결된 = "{}접속되어 있습니다. 접속_첫번째 = "접속하다{}먼저.  학급 충전 템플릿(메타클래스=ABC메타):      @http 방법     방어하다 충전하다(자신):         올리다 구현되지 않은 오류(미실장)  학급 포맷 IPhone(충전 템플릿):     @http 방법     방어하다 use_module(자신):         올리다 구현되지 않은 오류(미실장)  학급 포맷안드로이드(충전 템플릿):     @http 방법     방어하다 use_micro_usb(자신):         올리다 구현되지 않은 오류(미실장)  학급 IPhone(포맷 IPhone):     __name__ = '아이폰'      방어하다 __init__(자신):         자신.커넥터 = 거짓의      방어하다 use_module(자신):         자신.커넥터 = 진실의         인쇄물(연결된.포맷(POWER_어댑터[자신.__name__]))      방어하다 충전하다(자신):         한다면 자신.커넥터:             위해서   충전:                 인쇄물()         또 다른:             인쇄물(접속_첫번째.포맷(POWER_어댑터[자신.__name__]))  학급 안드로이드(포맷안드로이드):     __name__ = '안드로이드'      방어하다 __init__(자신):         자신.커넥터 = 거짓의      방어하다 use_micro_usb(자신):         자신.커넥터 = 진실의         인쇄물(연결된.포맷(POWER_어댑터[자신.__name__]))      방어하다 충전하다(자신):         한다면 자신.커넥터:             위해서   충전:                 인쇄물()         또 다른:             인쇄물(접속_첫번째.포맷(POWER_어댑터[자신.__name__]))  학급 IPhone 어댑터(포맷안드로이드):     방어하다 __init__(자신, 모바일.):         자신.모바일. = 모바일.      방어하다 충전하다(자신):         자신.모바일..충전하다()      방어하다 use_micro_usb(자신):         인쇄물(연결된.포맷(POWER_어댑터['안드로이드']))         자신.모바일..use_module()  학급 AndroidRecharger:     방어하다 __init__(자신):         자신.전화 = 안드로이드()         자신.전화.use_micro_usb()         자신.전화.충전하다()  학급 IPhone MicroUSBRecharger:     방어하다 __init__(자신):         자신.전화 = IPhone()         자신.phone_module = IPhone 어댑터(자신.전화)         자신.phone_module.use_micro_usb()         자신.phone_module.충전하다()  학급 IPhone 충전기:     방어하다 __init__(자신):         자신.전화 = IPhone()         자신.전화.use_module()         자신.전화.충전하다()  인쇄물("MicroUSB 충전기로 안드로이드 충전") AndroidRecharger() 인쇄물()  인쇄물("어댑터 패턴을 사용하여 MicroUSB로 아이폰을 충전합니다.) IPhone MicroUSBRecharger() 인쇄물()  인쇄물("아이폰 충전기로 아이폰 충전") IPhone 충전기() 

C#

일반의 인터페이스 ILightning Phone(전화기) {  무효 Connect Lightning(접속 라이트닝)();  무효 충전(); }  일반의 인터페이스 IUsbPhone {  무효 Connect Usb();  무효 충전(); }  일반의 밀봉된 학급 안드로이드폰 : IUsbPhone {  사적인 부울 접속되어 있다;    일반의 무효 Connect Usb()  {   이것..접속되어 있다 = 진실의;   콘솔.기입선("안드로이드 전화 연결");  }   일반의 무효 충전()  {   한다면 (이것..접속되어 있다)   {    콘솔.기입선("안드로이드 폰 충전");   }   또 다른   {    콘솔.기입선("먼저 USB 케이블을 연결합니다.");   }  } }  일반의 밀봉된 학급 애플폰 : ILightning Phone(전화기) {  사적인 부울 접속되어 있다;    일반의 무효 Connect Lightning(접속 라이트닝)()  {   이것..접속되어 있다 = 진실의;   콘솔.기입선("애플폰이 연결되었습니다.");  }   일반의 무효 충전()  {   한다면 (이것..접속되어 있다)   {    콘솔.기입선("애플폰 충전 중");   }   또 다른   {    콘솔.기입선("먼저 라이트닝 케이블을 연결합니다.");   }  } }  일반의 밀봉된 학급 Lightning To Ub 어댑터 : IUsbPhone {  사적인 읽기 전용 ILightning Phone(전화기) 라이트닝 폰;    사적인 부울 접속되어 있다;    일반의 Lightning To Ub 어댑터(ILightning Phone(전화기) 라이트닝 폰)  {   이것..라이트닝 폰 = 라이트닝 폰;   이것..라이트닝 폰.Connect Lightning(접속 라이트닝)();  }    일반의 무효 Connect Usb()  {   이것..접속되어 있다 = 진실의;   콘솔.기입선("어댑터 케이블이 연결되었습니다.");  }   일반의 무효 충전()  {   한다면 (이것..접속되어 있다)   {    이것..라이트닝 폰.충전();   }   또 다른   {    콘솔.기입선("먼저 USB 케이블을 연결합니다.");   }  } }  일반의 무효 주된() {  ILightning Phone(전화기) 애플폰 = 신규 애플폰();  IUsbPhone 어댑터 케이블 = 신규 Lightning To Ub 어댑터(애플폰);  어댑터 케이블.Connect Usb();  어댑터 케이블.충전(); } 

출력:

Apple 전화기가 연결되어 있습니다. 어댑터 케이블이 접속되어 있다. Apple 전화기의 충전. 

「 」를 참조해 주세요.

레퍼런스

  1. ^ a b Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Head First Design Patterns. O'Reilly Media. p. 244. ISBN 978-0-596-00712-6. OCLC 809772256. Archived from the original (paperback) on 2013-05-04. Retrieved 2013-04-30.
  2. ^ Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. pp. 139ff. ISBN 0-201-63361-2.
  3. ^ "The Adapter design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
  4. ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (paperback). Vol. 1. O'Reilly Media. pp. 243, 252, 258, 260. ISBN 978-0-596-00712-6. Retrieved 2012-07-02.
  5. ^ "The Adapter design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.