DI con Injector en Flutter

Alfredo Bautista Santos
4 min readDec 9, 2020

¡Buenas! En este post veremos como aplicar inyección de dependencias (DI) en Flutter usando Injector.

¿Qué es la inyección de dependencias o DI?

La inyección de dependencias (en inglés Dependency Injection, DI) es un patrón de diseño orientado a objetos, en el que se proporciona las instancias ya creadas en vez de ser la propia clase la que los cree.

Explicado de otra manera, nos permite configurar instancias fuera de su ámbito de uso, contribuyendo al desacople de los módulos de nuestro software, delegando en un componente la responsabilidad de creación de objetos de nuestra app.

Veámoslo con un ejemplo que siempre queda más claro.

Imaginemos que tenemos una clase que necesita de la interacción de otra u otras (sus dependencias), podríamos tener algo así:

En este fragmento, vemos como la clase inicializa sus propias dependencias (Los repositories) y nos encontraremos los siguientes problemas:

1. El interactor está fuertemente acoplado a sus dependencias, por lo que si cambia una de ella o queremos usar otra dependencia, tendremos que modificar esta clase.

2. No es testeable, si queremos crear sus test unitarios, veremos que no podemos mockear sus dependencias, por lo que estaremos llamando a servicios externos y no tendremos su control.

3. Si las dependencias a su vez tienen dependencias, tendremos un gran acople entre los módulos, llevando a un arquitectura mal gestionada y ocasionando una gran dificultad en cada mantenimiento o mejora. Por ejemplo, si los repositorios obtienen servicios que le permiten comunicarse con otros agentes, un cambio en un servicio deberá ser modificado en cada clase que tenga su construcción.

Veamos el mismo ejemplo, pero inyectando sus dependencias por el constructor de la clase.

Con este pequeño cambio obtenemos:

1. El cambio entre repositories que hereden del AbstractAuthRepository es instantáneo y sin la modificación del interactor.

2. Podemos mockear los servicios, inyectando servicios locales o usando paquetes como Mockito.

3. Las dependencias ya están construidas, por lo que sus dependencias o configuraciones son ignoradas por nuestro componente.

Esta flexibilidad es importantísima en proyectos grandes pero puede ser muy tedioso tener que pasar las dependencias en cada construcción del objeto, veamos un paquete que nos facilita esta configuración.

Instalación

Como es habitual, para usar una dependencia en Flutter, solo deberemos ir a pub.dev e añadirla a nuestro pubspec.yaml

Injector

Vemos los métodos que nos da el paquete para la creación de los objetos y su llamada en otros lugares de nuestra aplicación:

Registrar una dependencia

Usando el ejemplo anterior, vamos a registrar la dependencia del authRepository

Simplemente debemos construir una clase que herede de AbstractAuthRepository y devolverla en la callback que expone el método registerDependency

Obtener la dependencia

Como vemos en el anterior ejemplo, en el constructor le pasamos la referencia a la creación de la instancia, en ningún momento vemos cómo se construye, solo le indicamos de que tipo es la dependencia a inyectar.

Supongamos que el AuthInteractor es un singleton en nuestra aplicación. Vamos a definir su creación y llamada.

Registro de Singleton

La construcción de este objeto solo se hará una vez y será la misma instancia cada vez que llamemos a nuestro Injector, pudiendo almacenar información, en memoria, que será accesible en toda la app, sin tener que estar pasándolo a los diferentes componentes.

Uso en Flutter

Hasta ahora hemos visto su uso en Dart ¿Qué nos puede aportar en nuestra Flutter app?

Esta inyección de dependencias nos permite separar, de una forma muy sencilla, la parte de datos, de dominio y de UI de nuestra app. Podemos inyectar las dependencias que usará nuestra UI para interactuar con la lógica de negocio y a su vez con las dependencias externas. Veamos un ejemplo utilizando el patrón bloc

Definamos un AuthBloc (Capa de dominio) con sus dependencias (Capa de datos)

Y los repositorios que hemos usado anteriormente. Ahora vamos a inyectar todas nuestras dependencias dentro de una clase que será llamada antes del runApp();

En este archivo, tendremos todo el registro de todas las dependencias de nuestra app. Teniéndolo en este fichero, es mucho más fácil el intercambio de dependencia o la inyección de nuevas.

Ahora utilicémoslo en nuestra UI (Capa de UI)

Con esa sencilla llamada, ya tendremos disponible nuestro AuthBloc dentro de nuestro Widget tree y podemos utilizarlo en los objetos del paquete flutter_bloc como BlocBuilder, BlocListener…

Esta inyección nos permite abstraer la capa de UI de como se ha construido las dependencias de otras capas y su repetición en toda la UI, como tener que inyectarlo en otras rutas o crear nuevos BLoC.

El uso de DI también puede ser muy interesante para descomponer la construcción de nuestra UI, dividiendo la responsabilidad entre la creación de rutas y la creación de los Widget o páginas.

En el fichero anterior tenemos un pequeño ejemplo de cómo se llevaría a cabo, teniendo separado la parte del register y la de las rutas.

Por ultimo dejo os mi twitter dónde me encontraréis hablando sobre tecnología en general pero sobre todo Flutter 💙

¡Un saludo y hasta la próxima!

--

--

Alfredo Bautista Santos

Sysadmin and web developer. Co-organizer of GDGMarbella & FlutterConf in Marbella, Spain. Flutter enthusiastic.