
스위프트로 작성된 어댑터
어댑터는 구조 디자인 패턴이며, 호환되지 않는 객체들이 협업할 수 있도록 합니다.
어댑터는 두 객체 사이의 래퍼 역할을 합니다. 하나의 객체에 대한 호출을 캐치하고 두 번째 객체가 인식할 수 있는 형식과 인터페이스로 변환합니다.
복잡도:
인기도:
사용 예시들: 어댑터 패턴은 스위프트 코드에 자주 사용됩니다. 특히 일부 레거시 코드를 기반으로 하는 시스템에서 매우 자주 사용됩니다. 이러한 경우 어댑터는 레거시 코드가 현대식 클래스들과 함께 작동하도록 합니다.
식별: 어댑터는 다른 추상/인터페이스 유형의 인스턴스를 받는 생성자의 존재여부로 인식할 수 있습니다. 어댑터가 그의 메서드들에 대한 호출을 수신하면, 어댑터는 매개변수들을 적절한 형식으로 변환한 다음 해당 호출을 래핑 된 객체의 하나 또는 여러 메서드들에 전달합니다.
개념적인 예시
이 예시는 어댑터 디자인 패턴의 구조를 보여주고 다음 질문에 중점을 둡니다:
- 패턴은 어떤 클래스들로 구성되어 있나요?
- 이 클래스들은 어떤 역할을 하나요?
- 패턴의 요소들은 어떻게 서로 연관되어 있나요?
이 패턴의 구조를 배우면 실제 스위프트 사용 사례를 기반으로 하는 다음 예시를 더욱 쉽게 이해할 수 있을 것입니다.
Example.swift: 개념적인 예시
import XCTest /// The Target defines the domain-specific interface used by the client code. class Target { func request() -> String { return "Target: The default target's behavior." } } /// The Adaptee contains some useful behavior, but its interface is incompatible /// with the existing client code. The Adaptee needs some adaptation before the /// client code can use it. class Adaptee { public func specificRequest() -> String { return ".eetpadA eht fo roivaheb laicepS" } } /// The Adapter makes the Adaptee's interface compatible with the Target's /// interface. class Adapter: Target { private var adaptee: Adaptee init(_ adaptee: Adaptee) { self.adaptee = adaptee } override func request() -> String { return "Adapter: (TRANSLATED) " + adaptee.specificRequest().reversed() } } /// The client code supports all classes that follow the Target interface. class Client { // ... static func someClientCode(target: Target) { print(target.request()) } // ... } /// Let's see how it all works together. class AdapterConceptual: XCTestCase { func testAdapterConceptual() { print("Client: I can work just fine with the Target objects:") Client.someClientCode(target: Target()) let adaptee = Adaptee() print("Client: The Adaptee class has a weird interface. See, I don't understand it:") print("Adaptee: " + adaptee.specificRequest()) print("Client: But I can work with it via the Adapter:") Client.someClientCode(target: Adapter(adaptee)) } }
Output.txt: 실행 결과
Client: I can work just fine with the Target objects: Target: The default target's behavior. Client: The Adaptee class has a weird interface. See, I don't understand it: Adaptee: .eetpadA eht fo roivaheb laicepS Client: But I can work with it via the Adapter: Adapter: (TRANSLATED) Special behavior of the Adaptee.
실제 사례 예시
Example.swift: 실제 사례 예시
import XCTest import UIKit /// Adapter Design Pattern /// /// Intent: Convert the interface of a class into the interface clients expect. /// Adapter lets classes work together that couldn't work otherwise because of /// incompatible interfaces. class AdapterRealWorld: XCTestCase { /// Example. Let's assume that our app perfectly works with Facebook /// authorization. However, users ask you to add sign in via Twitter. /// /// Unfortunately, Twitter SDK has a different authorization method. /// /// Firstly, you have to create the new protocol 'AuthService' and insert /// the authorization method of Facebook SDK. /// /// Secondly, write an extension for Twitter SDK and implement methods of /// AuthService protocol, just a simple redirect. /// /// Thirdly, write an extension for Facebook SDK. You should not write any /// code at this point as methods already implemented by Facebook SDK. /// /// It just tells a compiler that both SDKs have the same interface. func testAdapterRealWorld() { print("Starting an authorization via Facebook") startAuthorization(with: FacebookAuthSDK()) print("Starting an authorization via Twitter.") startAuthorization(with: TwitterAuthSDK()) } func startAuthorization(with service: AuthService) { /// The current top view controller of the app let topViewController = UIViewController() service.presentAuthFlow(from: topViewController) } } protocol AuthService { func presentAuthFlow(from viewController: UIViewController) } class FacebookAuthSDK { func presentAuthFlow(from viewController: UIViewController) { /// Call SDK methods and pass a view controller print("Facebook WebView has been shown.") } } class TwitterAuthSDK { func startAuthorization(with viewController: UIViewController) { /// Call SDK methods and pass a view controller print("Twitter WebView has been shown. Users will be happy :)") } } extension TwitterAuthSDK: AuthService { /// This is an adapter /// /// Yeah, we are able to not create another class and just extend an /// existing one func presentAuthFlow(from viewController: UIViewController) { print("The Adapter is called! Redirecting to the original method...") self.startAuthorization(with: viewController) } } extension FacebookAuthSDK: AuthService { /// This extension just tells a compiler that both SDKs have the same /// interface. }
Output.txt: 실행 결과
Starting an authorization via Facebook Facebook WebView has been shown /// Starting an authorization via Twitter The Adapter is called! Redirecting to the original method... Twitter WebView has been shown. Users will be happy :)