Comunicación entre componentes débilmente acoplados

Nota:

Este libro electrónico se publicó en primavera de 2017 y no se ha actualizado desde entonces. Hay mucho en el libro que sigue siendo valioso, pero algunos de los materiales están obsoletos.

El patrón de publicación y suscripción es un patrón de mensajería en el que los publicadores envían mensajes sin tener conocimiento de los destinatarios, que se conocen como suscriptores. Del mismo modo, los suscriptores escuchan mensajes específicos, sin tener conocimiento de ningún publicador.

Los eventos de .NET implementan el patrón de publicación y suscripción, y son el enfoque más sencillo para una capa de comunicación entre los componentes si no se requiere el acoplamiento flexible, como sucede con un control y la página que lo contiene. Pero las duraciones del publicador y del suscriptor están acopladas por referencias a objetos, y el tipo de suscriptor debe tener una referencia al tipo de publicador. Esto puede generar problemas de administración de memoria, en especial cuando hay objetos de corta duración que se suscriben a un evento de un objeto estático o de larga duración. Si no se quita el controlador de eventos, el suscriptor se mantendrá activo mediante la referencia a él en el publicador y esto impedirá o retrasará la recolección de elementos no utilizados del suscriptor.

Introducción a MessagingCenter

La Xamarin.FormsMessagingCenter clase implementa el patrón publish-subscribe, lo que permite la comunicación basada en mensajes entre componentes que no son convenientes para vincular por referencias de objeto y tipo. Este mecanismo permite a los publicadores y suscriptores comunicarse sin que exista una referencia entre sí, lo que ayuda a reducir las dependencias entre los componentes, a la vez que permite desarrollar y probar esos componentes de forma independiente.

La clase MessagingCenter proporciona la funcionalidad de publicación y suscripción de multidifusión. Esto significa que puede haber varios publicadores que publican un único mensaje y varios suscriptores que escuchen el mismo mensaje: En la figura 4-1 se muestra esta relación:

Funcionalidad de publicación y suscripción de multidifusión

Figura 4-1: Funcionalidad de publicación y suscripción de multidifusión

Los publicadores envían mensajes con el método MessagingCenter.Send, mientras que los suscriptores escuchan mensajes con el método MessagingCenter.Subscribe. Además, en caso necesario, los suscriptores también pueden cancelar la suscripción a mensajes con el método MessagingCenter.Unsubscribe.

Internamente, la clase MessagingCenter utiliza referencias débiles. Esto significa que no mantendrá los objetos activos y permitirá la recolección de elementos no utilizados. Por lo tanto, solo debería ser necesario cancelar la suscripción a un mensaje cuando una clase ya no quiere recibir el mensaje.

La aplicación móvil eShopOnContainers usa la MessagingCenter clase para comunicarse entre componentes de acoplamiento flexible. La aplicación define tres mensajes:

  • La clase CatalogViewModel publica el mensaje AddProduct cuando se agrega un elemento a la cesta de la compra. A cambio, la BasketViewModel clase se suscribe al mensaje e incrementa el número de artículos de la cesta de la compra en respuesta. Además, la clase también cancela la BasketViewModel suscripción de este mensaje.
  • El Filter mensaje lo publica la CatalogViewModel clase cuando el usuario aplica un filtro de marca o tipo a los elementos mostrados desde el catálogo. A cambio, la CatalogView clase se suscribe al mensaje y actualiza la interfaz de usuario para que solo se muestren los elementos que coincidan con los criterios de filtro.
  • La ChangeTab clase publica el MainViewModel mensaje cuando CheckoutViewModel navega a la MainViewModel siguiente creación y envío correctos de un nuevo pedido. A cambio, la MainView clase se suscribe al mensaje y actualiza la interfaz de usuario para que la pestaña Mi perfil esté activa, para mostrar los pedidos del usuario.

Nota

Aunque la clase MessagingCenter permite la comunicación entre clases de acoplamiento impreciso, no ofrece la única solución arquitectónica a este problema. Por ejemplo, la comunicación entre un modelo de vista y una vista también se puede lograr mediante el motor de enlace y a través de notificaciones de cambio de propiedad. Asimismo, la comunicación entre dos modelos de vista también se puede lograr pasando datos durante la navegación.

En la aplicación móvil eShopOnContainers, MessagingCenter se usa para actualizar en la interfaz de usuario en respuesta a una acción que se produce en otra clase. Por lo tanto, los mensajes se publican en el subproceso de la interfaz de usuario, con suscriptores que reciben el mensaje en el mismo subproceso.

Sugerencia

Serializar el subproceso de la interfaz de usuario al realizar actualizaciones de la interfaz de usuario. Si para actualizar la interfaz de usuario se requiere un mensaje enviado desde un subproceso en segundo plano, procese dicho mensaje en el subproceso de interfaz de usuario del suscriptor, invocando para ello el método Device.BeginInvokeOnMainThread.

Para obtener más información sobre MessagingCenter, vea MessagingCenter.

Definición de un mensaje

Los mensajes MessagingCenter son cadenas que se usan para identificar mensajes. En el ejemplo de código siguiente se muestran los mensajes definidos en la aplicación móvil eShopOnContainers:

public class MessageKeys  
{  
    // Add product to basket  
    public const string AddProduct = "AddProduct";  

    // Filter  
    public const string Filter = "Filter";  

    // Change selected Tab programmatically  
    public const string ChangeTab = "ChangeTab";  
}

En este ejemplo, los mensajes se definen mediante constantes. La ventaja de este método reside en que ofrece seguridad de los tipos en tiempo de compilación y compatibilidad con la refactorización.

Publicación de un mensaje

Los publicadores informan a los suscriptores de un mensaje con una de las sobrecargas de MessagingCenter.Send. En el ejemplo de código siguiente se muestra cómo publicar el mensaje AddProduct:

MessagingCenter.Send(this, MessageKeys.AddProduct, catalogItem);

En este ejemplo, el Send método especifica tres argumentos:

  • El primer argumento especifica la clase del emisor. La clase del emisor la deben especificar aquellos suscriptores que quieran recibir el mensaje.
  • El segundo argumento especifica el mensaje.
  • El tercer argumento especifica los datos de carga que se van a enviar al suscriptor. En este caso, los datos de carga son una CatalogItem instancia de .

El método Send publicará el mensaje y sus datos de carga mediante un enfoque del tipo "dispara y olvida". Por lo tanto, el mensaje se envía incluso aunque no haya ningún suscriptor registrado para recibir el mensaje. En esta situación, se omite el mensaje enviado.

Nota

El método MessagingCenter.Send puede usar parámetros genéricos para controlar cómo se entregan los mensajes. En consecuencia, distintos suscriptores podrán recibir varios mensajes que compartan una identidad de mensaje, pero que envíen diferentes tipos de datos de carga.

Suscribirse a un mensaje

Los suscriptores pueden registrarse para recibir un mensaje mediante una de las sobrecargas de MessagingCenter.Subscribe. En el ejemplo de código siguiente se muestra cómo se suscribe la aplicación móvil eShopOnContainers y los procesos, el AddProduct mensaje:

MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(  
    this, MessageKeys.AddProduct, async (sender, arg) =>  
{  
    BadgeCount++;  

    await AddCatalogItemAsync(arg);  
});

En este ejemplo, el Subscribe método se suscribe al AddProduct mensaje y ejecuta un delegado de devolución de llamada en respuesta a la recepción del mensaje. Este delegado de devolución de llamada, especificado como una expresión lambda, ejecuta código que actualiza la interfaz de usuario.

Sugerencia

Considere la posibilidad de usar datos de carga inmutables. No intente modificar los datos de carga desde un delegado de devolución de llamada porque varios subprocesos podrían tener acceso a los datos recibidos simultáneamente. En este escenario, los datos de carga deben ser inmutables para evitar errores de simultaneidad.

Es posible que un suscriptor no necesite controlar cada instancia de un mensaje publicado, lo cual se puede controlar mediante los argumentos de tipo genérico que se especifican en el método Subscribe. En este ejemplo, el suscriptor solo recibirá AddProduct mensajes enviados desde la CatalogViewModel clase , cuyos datos de carga son una CatalogItem instancia de .

Anulación de la suscripción de un mensaje

Los suscriptores pueden cancelar la suscripción a los mensajes que ya no quieren recibir. Esto se logra con uno de las sobrecargas MessagingCenter.Unsubscribe, como se muestra en el ejemplo de código siguiente:

MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct);

En este ejemplo, la sintaxis del Unsubscribe método refleja los argumentos de tipo especificados al suscribirse para recibir el AddProduct mensaje.

Resumen

La Xamarin.FormsMessagingCenter clase implementa el patrón publish-subscribe, lo que permite la comunicación basada en mensajes entre componentes que no son convenientes para vincular por referencias de objeto y tipo. Este mecanismo permite a los publicadores y suscriptores comunicarse sin que exista una referencia entre sí, lo que ayuda a reducir las dependencias entre los componentes, a la vez que permite desarrollar y probar esos componentes de forma independiente.