Photo by Cupcake Media on Unsplash

Un Flutter Más Limpio Vol. 8: Implementando contratos

Pagando la deuda

Marcos Sevilla
Published in
3 min readMay 12, 2021

--

Ya hemos hablado de repositorios, diría que bastante. Pero aún nos queda una parte más que cubrir sobre ellos, su implementación. A este punto de los volúmenes de la serie, hemos establecido acciones que queremos efectuar por medio de DataSources.

En general, la implementación de un repositorio es sencilla. Ya que sólo son una clase que administra las fuentes de datos y, mediante ellas, crea un flujo de datos completo.

En el volumen anterior vimos sobre DataSources o DataProviders, así que vamos a incluirlos como dependencias de nuestro repositorio.

Nuestro repositorio igualmente implementa al repositorio interfaz (o abstracto) que hicimos desde la capa de dominio, sobreescribiendo sus métodos más adelante.

También podemos ver el patrón de inyección de dependencias que me gusta seguir, manteniendo las variables privadas y sólo asignándole el valor de una variable declarada únicamente a nivel del constructor.

Esta forma de usar las variables privadas con la inyección de dependencias nos limita a utilizar esta dependencia única e indirectamente por métodos del objeto, evitando su uso directo como propiedad.

Vamos a sobreescribir el método getModel() que establece nuestro repositorio abstracto para utilizar nuestros DataSources y definir un flujo específico de datos.

El método getModel() es el encargado de traer un dato específico en una lista basado en un ID. Este método ocupa el remoteDataSource para consultar el dato al API REST y de aquí desencadenan dos posibles escenarios:

  1. Si el API responde correctamente, entonces el dato es guardado localmente por el localDataSource.
  2. Si el API tuvo un error, entonces se obtiene el último valor guardado localmente. En el caso de que no haya un valor guardado, se lanza un error de cache.

El código se ve de la siguiente manera…

Entonces podemos ver que nuestro repositorio sirve como intermediario para una acción concreta. No nos interesa si los datos vienen por HTTP o algún otro protocolo, de eso se encarga un DataSource. Tampoco si se guarda en preferencias de usuario o algún almacenamiento seguro.

Nos interesa la acción en específico de traer un elemento, de lo que vienen distintos pasos más a detalle del proceso donde convergen varias posibles formas de interactuar con estos datos.

Por lo anterior, dejamos interfaces o clases abstractas de los DataSource para que sean fácilmente sustituidas por otras implementaciones. Eso nos permite cambiar un DataSource que ocupe el paquete de shared_preferences por uno que ocupe hive y haga exactamente lo mismo. Así se sigue el Principio de Sustitución de Liskov.

Lo de siempre…

Si aprendiste algo nuevo y te fue de utilidad, podés compartir este artículo para ayudar a otro/a desarrollador(a) a seguir mejorando su productividad y calidad al escribir aplicaciones con Flutter.

También hay una versión de este mismo artículo en inglés publicado en dev.to. De nada. 🇺🇸

Además, si te gustó este contenido, podés encontrar aún más y seguir en contacto conmigo en mis redes sociales:

  • dev.to — donde publico versiones en inglés de mis artículos.
  • GitHub — donde están mis repositorios de código, por si te gustan los ejemplos.
  • LinkedIn — donde conecto profesionalmente.
  • Medium — donde estás leyendo este artículo.
  • Twitter — donde expreso mis ideas cortas y comparto mi contenido.
  • Twitch — donde hago directos informales de los que saco clips con información puntual.
  • YouTube — donde publico los clips que salen de mis directos.

Originally published at http://github.com.

--

--