Antes de ponernos manos a la obra vamos a ver por qué nos viene bien utilizar este patrón.
Tenemos una aplicación en la que sus datos pueden estar en diferentes sitios: Core Data, Realm, SQLite, memoria, preferencias de usuario, servidor… Cada vez que necesitemos unos datos, nos vamos a tener que preocupar de dónde están y de cómo cogerlos, por no decir que en cada parte del código donde los pidamos tendríamos que repetir todo el proceso.
Utilizando este patrón conseguimos abstraer todas nuestras fuentes de datos en una misma clase, de tal manera que fuera de esa clase no nos preocupa de dónde saquemos los datos.
Por poner una definición formal: patrón de diseño que abstrae el dominio o capa de negocio de la persistencia (acceso a datos). Actúa como intermediario entre estas dos partes de nuestra aplicación.
Como podemos ver, es nuestra lógica de negocio la que se comunica con el Repositorio y éste el que se preocupa de comunicarse con el Data Source. ¿Que qué son Data Source y Data Mapper que se ven en la infografía?:
- Data Source: fuente de datos, por ejemplo el disco duro o un servidor.
- Data Mapper: clase que mapea los datos que llegan del Data Source para que sean válidos en la lógica de negocio.
En nuestro ejemplo veremos cómo añadir tantos Data Sources como necesitemos a nuestro Repositorio.
¿Y cómo se hace?
Ahora que ya sabemos si vamos a necesitar usar este patrón, vamos a ver cómo hacerlo.
Primero creamos nuestra clase «Repositorio» con las variables que vamos a necesitar.
Vamos por partes, inicialmente tenemos nuestro delegado RepositoyDelegate, con un método que nos avisa cuando los objetos del Repositorio han cambiado.
Justo debajo tenemos nuestra clase «Repositorio», la cual tiene un template que implementa la clase «Parseable» (esta clase «Parseable» serán nuestros mappers ). No es más que un interface con la función encargada de mapear los datos.
Al final tenemos nuestros dos Data Sources, cada uno abstraído con su respectivo interface (PersistenceClient, NetworkClient ). En nuestro ejemplo vamos a usar Realm para la persistencia y una clase para conectarnos con el servidor.
La comunicación entre nuestra capa de negocio y el Repositorio la haremos a través de una función de la clase «Repositorio».
La función recibe por parámetros la operación de red BaseOperation. Es la clase que encapsula los datos necesarios para realizar la operación de red y un bloque (closure en Swift) el cual devuelve un flag persist, que nos indica si el Repositorio ha cogido la información de persistencia.
Primero comprobamos si disponemos de los datos dentro de nuestro persistenceDataSource, si así es llamamos a la función del delegado y al closure completion.
Si no disponemos de estos datos en nuestra persistencia, el Repositorio los pedirá a servidor.
Una vez recogidos de servidor, se encargará de escribirlos en persistencia para futuras cargas.
En esta parte hemos utilizado dos funciones de utilidad privadas de nuestro Repositorio.
Con esto, tenemos nuestro Repositorio terminado. Ahora veamos cómo usarlo.
¿Cómo se usa un Repositorio?
Gracias a que lo hemos hecho con genéricos, podremos usar cualquier clase, siempre y cuándo esta implemente nuestro mapper Parseable.
Primero nos creamos la operación que encapsula los parámetros para pedir los datos a servidor; después nuestro Repositorio, de la clase «User«, que es la que implementa Parseable; añadimos el delegado y llamamos a la función.
De esta manera estén donde estén los usuarios, nuestro Repositorio los va a buscar en persistencia o en el servidor, y gracias a que hemos implementado con genéricos, podemos pedir cualquier tipo de dato sin necesidad de modificarlo.
Consulta con nuestro equipo si quieres que te ayudemos en este proceso.