O Adapter é um padrão de projeto estrutural, que permite a colaboração de objetos incompatíveis.
O Adapter atua como um wrapper entre dois objetos. Ele captura chamadas para um objeto e as deixa reconhecíveis tanto em formato como interface para este segundo objeto.
Exemplo conceitual
Este exemplo ilustra a estrutura do padrão de projeto Adapter . Ele se concentra em responder a estas perguntas:
De quais classes ele consiste?
Quais papéis essas classes desempenham?
De que maneira os elementos do padrão estão relacionados?
Depois de aprender sobre a estrutura do padrão, será mais fácil entender o exemplo a seguir, com base em um caso de uso Swift do mundo real.
Example.swift: Exemplo conceitual
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: Resultados da execução
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.
Exemplo do mundo real
Example.swift: Exemplo do mundo real
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: Resultados da execução
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 :)