Análisis de Widget heredado en Flutter/Habr

Widget heredado: ¿antipatrón?

El localizador de servicios es malvado. InheritedWidget es un servicio de localización con restricciones.
En este artículo, descubriremos cómo el servicio de localización resuelve estas limitaciones y si resuelven…

Por qué InheritedWidget es mejor que la transferencia de dependencia

Si se crea una dependencia en un componente de alto nivel y se usa en un nivel bajo, surgen problemas con su transferencia. Pasar dependencias a través de parámetros del constructor de componentes intermedios causará muchos problemas desde el punto de vista del diseño (romperá las interfaces de clases, romperá SRP, DIP, encapsulación, etc.)

El localizador de servicios es la solución más sencilla a este problema. Pero crea aún más problemas, por lo que no debería utilizarse.

Esto hace que el patrón InheritedWidget sea interesante de usar.

Cómo utilizar el widget heredado

Si InheritedWidget ensambla de forma independiente servicios directamente encima del widget que usa estos servicios, entonces este enfoque es equivalente al enfoque en el que el widget que usa dependencias crea estas dependencias de forma independiente.

La fuerte conexión entre el cliente y la adicción no desaparece, lo que causa muchos problemas. Por ejemplo, un servicio creado de esta manera no se puede probar, ya que dependerá del contexto; solo se puede probar en un widget ubicado debajo de InheritedWidget.

Primicia del widget heredado

Un InheritedWidget tiene un alcance de acceso a los servicios registrados en él, que está limitado a su subárbol de widgets secundarios. es decir, se puede acceder a sus servicios mediante cualquier widget de su subárbol secundario, en lugar de cualquier componente de la aplicación.

Solo se puede acceder a los servicios de InheritedWidget a través del contexto, y otros componentes del sistema que no están ubicados en el lugar correcto en el árbol de widgets (en InheritedWidget) no pueden acceder a ellos. Si InheritedWidget es responsable de ensamblar el servicio al que ofrece acceso, entonces probar ese servicio se vuelve difícil, ya que los componentes de prueba tendrán que residir debajo de InheritedWidget.

Por lo tanto, InheritedWidget no debe ser responsable de ensamblar servicios. Todos los servicios de la aplicación deben ensamblarse en un contenedor DI, que debe estar ubicado en la raíz de la composición. De esta forma, será posible probar todos los servicios utilizados en la aplicación.

InheritedWidget puede obtener por sí mismo las dependencias que necesita y utilizar el contenedor DI en la raíz de la composición como localizador de servicios, pero existen muchos problemas al utilizar un localizador de servicios, por lo que este método no es adecuado.

El inyector, ubicado en la raíz de la composición, debe implementar todas las dependencias que necesita a través del constructor InheritedWidget. Si InheritedWidget está ubicado en lo profundo del árbol de widgets, entonces habrá un problema con la transferencia de dependencias a través de los constructores de widgets del árbol intermedio. Por lo tanto, InheritedWidget debe ser un widget de alto nivel y estar ubicado cerca de la raíz del árbol de widgets.
Lo más lógico es utilizar InheritedWidgets como proveedor de servicios utilizados en las pantallas de aplicaciones. Así, InheritedWidgets deberían ser los widgets raíz de la pantalla y requerir, a través de su constructor, del inyector todas las dependencias utilizadas en la pantalla.

Servicios de pantalla en InheritedWidget

Los servicios deben crearse de forma perezosa sólo cuando se está construyendo la pantalla en la que se utilizarán.

Después de desechar la pantalla, los servicios que se utilizaron en ella ya no se utilizarán, por lo que deben desecharse junto con la pantalla. De lo contrario, se producirá una fuga de recursos.

Usar un contenedor DI inteligente, como el que proporciona el paquete get_it, puede ayudar con esto.

Problema inflado del widget heredado

Si los InheritedWidgets son componentes de alto nivel en la raíz de la pantalla, entonces pueden convertirse en un repositorio demasiado grande de dependencias que se utilizan dentro de todo el subárbol de la pantalla.

Al mismo tiempo, hay servicios que solo pueden ser utilizados por widgets de bajo nivel, pero como están disponibles para cualquier widget en el subárbol de un widget cifrado, los widgets intermedios para los que no están destinados también pueden acceder a ellos, lo cual es no muy seguro.

Eso. hay una violación del principio de menor conocimiento. Si una clase puede ignorar algún aspecto del sistema y aun así hacer un buen trabajo, entonces ahórrele los detalles innecesarios.

Si todos los widgets del subárbol InheritedWidget, que es responsable de todos los servicios de la pantalla, pueden acceder a cualquier servicio del Inherited Widget, entonces esto es normal, ya que todos estos servicios deben usarse en esta pantalla. Y por lo tanto, no hay necesidad de limitar injustificadamente el acceso a los servicios dentro de diferentes widgets de su subárbol. Sin embargo, hay casos en los que esto se puede hacer.

Restringir el acceso a los servicios de InheritedWidget.

El problema con InheritedWidget es que el acceso a los servicios registrados en él, que están destinados a widgets de subárbol de bajo nivel, se otorga a widgets ubicados en un nivel superior de los widgets de destino. No deberían tener acceso a estos servicios por el principio de menor conocimiento, para no tener acceso a funciones e información a las que no deberían tener acceso.

Puede restringir el acceso de los widgets a servicios peligrosos con efectos secundarios. Por ejemplo, un servicio para modificar configuraciones de pantalla (servicio de navegación entre pantallas de aplicaciones) se puede brindar solo a un widget de pantalla de alto nivel, y a todos los demás servicios sin importancia se les puede brindar acceso ilimitado.

Para implementar la restricción de acceso a los servicios de InheritedWidget, debe crear un sistema de alcance dentro de la pantalla de InheritedWidget, que permita que solo ciertos widgets de subárbol accedan a sus servicios; por ejemplo, un widget que tiene un determinado tipo de datos de la clase de widget personalizada.

Un InheritedWidget, cuando se accede desde un widget de su soporte, recibe un contexto, un elemento correspondiente al widget que realiza esta llamada. A partir del contexto, InheritedWidget puede comprender qué widget de subárbol está intentando acceder a un servicio específico que está registrado en él. es decir, en InheritedWidget debe registrar widgets de soporte, clases que pueden acceder a ciertos servicios almacenados en su interior.

Comparación con localizador de servicios.

InheritedWidget no es un objeto global, a diferencia de un localizador de servicios.
InheritedWidget es mejor que un localizador de servicios porque cada InheritedWidget almacena servicios relacionados con una pantalla determinada, y no con todas las pantallas de aplicaciones y otros componentes de la aplicación, como sucede en un localizador de servicios.

InheritedWidget le permite mantener la interfaz abierta, a diferencia del servicio de localización.
Si un widget usa InheritedWidget para obtener dependencias, esto se refleja en su interfaz. Una solicitud a un InheritedWidget proviene de métodos de widget especiales que forman parte de su interfaz. Estos métodos recuperan dependencias de InheritedWidget y las configuran como valores de campo de dependencia.
Esto le permite realizar un seguimiento de la complejidad de los widgets (si un widget tiene demasiadas dependencias, se vuelve demasiado complejo y es necesario solucionar este problema).
También le permite conocer la responsabilidad del widget: por dependencias puede determinar qué hace el widget (por ejemplo, si hay una dependencia en forma de repositorio para enviar una solicitud de registro, entonces el widget es responsable de pantalla de registro).

Conclusión

Service Locator es malo y InheritedWidget es el mal menor.
InheritedWidget es un compromiso entre un localizador de servicios, el widget que resuelve de forma independiente sus dependencias y reenvía las dependencias a través de los constructores de widgets intermedios.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *