Patrón de diseño: ADAPTER

Patrón de diseño: ADAPTER

El patrón Adapter es muy útil al integrar en nuestra codebase código de terceros y que no podemos modificar. Hoy vamos a ver un ejemplo real cuando integramos un SDK de terceros, como el SDK de Twitter

SwiftBeta

Hoy vamos a ver el patrón Adapter, un patrón de diseño que es estructural. El patrón Adapter nos sirve para usar dos componentes que tienen interfaces totalmente distintas.

Lo podemos asociar también a elementos físicos, como un multiadaptador de corriente que te llevas cuando viajas a distintas partes del mundo.

¿Cuándo lo usamos? Cuando no podemos modificar el código ya que lo estamos usando de terceros. Imagínate el SDK de una empresa de Analytics, o el SDK de Twitter por ejemplo.

Podemos crearlo extendiendo el comportamiento de una clase o creando una clase adapter que encapsularía el código de terceros, es decir, creamos un wrapper.

Vamos a ver un ejemplo:

struct TwitterUser {
    let name: String
    let email: String
    let token: String
}

class TwitterSDK {
    
    func authenticate(email: String, password: String, completion: (TwitterUser?, Error?) -> ()) {
        let twitterUser = TwitterUser(name: "SwiftBeta", email: "swiftbeta@email.com", token: "my-token")
        completion(twitterUser, nil)
    }
    
}

El código anterior suponemos que vendría dentro del SDK de Twitter, y por lo tanto no lo podemos modificar (o no deberíamos bajo ningún concepto).

En lugar de depender del SDK de Twitter directamente en nuestro código, podemos crear un protocolo de autenticación que pueda ser usado por más SDKs (Facebook, Google, Slack, etc). Esta interfaz nos va a servir para que no acoplemos código de los SDKs directmente en nuestra codebase.

Creamos el siguiente protocolo (que nos serviría también para futuros login con otros SDK como hemos mencionado antes):

protocol AuthService {
    func authenticate(email: String, password: String, onSuccess: (User) -> (), onFailure: (Error?) -> ())
}

struct User {
    let name: String
    let email: String
    let token: String
}

Ahora lo que podemos hacer son dos cosas, extender el comportamiento del SDK de Twitter o crear una clase adapter que encapsula el SDK de Twitter (es decir, creamos un wrapper). En este caso vamos a crear una clase.

class TwitterSDKAdapter: AuthService {
    private let twitterSDK = TwitterSDK()
    
    func authenticate(email: String, password: String, onSuccess: (User) -> (), onFailure: (Error?) -> ()) {
        twitterSDK.authenticate(email: email, password: password) { (twitterUser, error) in
            guard let twitterUser = twitterUser else {
                onFailure(error)
                return
            }
            
            onSuccess(.init(name: twitterUser.name,
                            email: twitterUser.email,
                            token: twitterUser.token)
            )
        }
    }
}

Como ves, hemos creado un wrapper donde comunicamos el SDK de Twitter con nuestro código. Transformamos su dominio a nuestro propio dominio.

Esto es realmente útil ya que si algún día decidimos añadir más SDK para autenticar dentro de nuestra aplicación (como por ejemplo añadir el de Facebook) sería muy fácil. Nos crearíamos otra clase que se llame FacebookSDKAdapter que conforme el protcolo AuthService y así creamos consistencia dentro de nuestra aplicación.


Hasta aquí el post de hoy, gracias por leernos! 🤓
Si tienes preguntas no dudes en contactar con nosotros a través de Twitter

Si quieres seguir aprendiendo sobre SwiftUI, Swift, Xcode, o cualquier tema relacionado con el ecosistema Apple


Patrones