2008-11-17 9 views
6

Tengo una aplicación que consta de varios ensamblajes diferentes, uno de los cuales contiene las diversas interfaces que obedecen las clases, y mediante el cual las clases se comunican a través de los límites del ensamblaje. Hay varias clases que disparan eventos, y varias que están interesadas en estos eventos.C# Mejor práctica: controlador de eventos centralizado o no

Mi pregunta es la siguiente: ¿es una buena práctica implementar un EventConsolidator central de algún tipo? Esto estaría altamente acoplado, ya que necesitaría conocer cada clase (o al menos su interfaz) lanzando un evento, y cada consumidor de un evento necesitaría tener una referencia a EventConsolidator para poder suscribirse.

Actualmente tengo la situación en que la clase A conoce la clase B (pero no C), la clase B conoce la clase C, etc. Luego, si C desencadena un evento B necesita recogerlo y activar su propio evento para A responder. Este tipo de cadenas puede ser bastante larga, y es posible que B solo esté interesado en el evento para poder transmitirlo. No quiero que A sepa sobre C, ya que eso rompería la encapsulación.

¿Qué es una buena práctica en esta situación? Centralizar los eventos, o sonreír y soportar y definir eventos en cada clase intermedia? ¿O cuáles son los criterios para tomar la decisión? ¡Gracias!

Editar: Here es otra pregunta que pregunta esencialmente lo mismo.

Respuesta

8

Puede poner el evento en una interfaz, de modo que A no necesita saber acerca de C directamente, sino solo que tiene el evento relevante. Sin embargo, quizás quiera decir que la instancia de A no tiene vista de una instancia de C ...

Intentaré alejarme de un sistema centralizado de eventos. Es probable que haga las pruebas más difíciles e introdujo un acoplamiento firme como usted dijo.

Un patrón que vale la pena conocer está simplificando el proxy de eventos.Si B sólo expone a un evento de proxy en C, que puede hacer:

public event FooHandler Foo 
{ 
    add 
    { 
     c.Foo += value; 
    } 
    remove 
    { 
     c.Foo -= value; 
    } 
} 

De esa manera se proxy de suscripción/desuscripción más que el acto de elevar el evento. Esto tiene un impacto en la elegibilidad para GC, por supuesto, que puede ser beneficioso o no, dependiendo de la situación. Vale la pena pensar sin embargo.

+0

Gracias Jon, al instante útiles como siempre! Eso era lo que estaba buscando en este caso, salud. –

+4

Una palabra de advertencia. Puede ser muy confuso cuando el valor "remitente" no es el objeto al que se suscribió. – Andreas

1

Probablemente intentaré masajear el dominio para que cada clase pueda depender directamente de la fuente del evento apropiado. Lo que quiero decir es hacer la pregunta ¿por qué A no sabe acerca de C? ¿Hay quizás una D esperando para salir?

Como un enfoque alternativo podría considerar una arquitectura de corredor de eventos. Significa que los observadores no saben directamente sobre la fuente. Aquí hay un interesante video.

1

Esto sería altamente acoplado, ya que tendría que conocer todas las clases

Creo que responde a su propia pregunta si se tiene en cuenta que el acoplamiento es malo! Pasar eventos a través de una cadena de manipuladores potenciales es un patrón bastante común en muchos entornos; Puede que no sea el enfoque más eficiente, pero evita la complejidad que su enfoque sugerido implicaría.

Otro enfoque que podría tomar es utilizar un despachador de mensajes. Esto implica utilizar un formato de mensaje común (o al menos un formato de encabezado de mensaje común) para representar eventos y luego colocar esos mensajes en una cola. A continuación, un despachador recoge cada uno de esos sucesos (o según una determinada prioridad) y los dirige directamente al controlador requerido. Cada controlador debe estar registrado con el despachador al inicio.

Un mensaje en este caso podría ser simplemente una clase con algunos campos específicos al comienzo. El mensaje específico podría ser simplemente un derivado, o podría pasar sus datos específicos del mensaje como un parámetro 'objeto' junto con el encabezado del mensaje.

6

Lo que podría intentar es utilizar el corretaje de eventos de NInject o el Unity Application Block.

Esto le permite, por ejemplo:

[Publish("foo://happened")] 
public event EventHandler<FooArgs> FooHappened; 

[Subscribe("foo://happened")] 
public void Foo_Happened(object sender, FooArgs args) 
{ } 

Si ambos objetos son creados a través del contenedor de los eventos serán conectados automáticamente.

1

Puede consultar el objeto EventBroker en los patrones M $ y practica lib si desea eventos centralizados.

Personalmente creo que es mejor pensar en su arquitectura en su lugar y, aunque usamos el EventBroker aquí, ninguno de nuestros nuevos códigos lo usa y esperamos eliminarlo un día soleado.

0

tenemos nuestra propia implementación gestor de eventos (open source) Tutorial en: http://sourceforge.net/apps/mediawiki/bbvcommon/index.php?title=Event_Broker

Y un análisis de rendimiento en: www.planetgeek.ch/2009/07/12/event-broker-performance/

ventajas en comparación con CAB: - mejor registro de - apoyo a la extensión - mejor manejo de errores - manipuladores extensibles (IU, subproceso de fondo, ...) y algo más que no recuerdo en este momento.

Cheers, Urs

Cuestiones relacionadas