Estoy construyendo una aplicación WinForms con una interfaz de usuario que solo consiste en NotifyIcon
y su ContextMenuStrip
dinámicamente poblado. Hay un MainForm
para mantener la aplicación en conjunto, pero eso nunca es visible.IoC: cableando dependencias en controladores de eventos
Me propuse construir esto lo más SOLIDAMENTE posible (usando Autofac para manejar el gráfico de objetos) y estoy bastante satisfecho con mi éxito, la mayoría de las veces me llevo muy bien incluso con la parte O. Con la extensión que estoy implementando, parece que descubrí un defecto en mi diseño y necesito remodelarlo un poco; Creo que sé cómo debo ir, pero no estoy seguro de cómo definir exactamente las dependencias.
Como se mencionó anteriormente, el menú se rellena en parte dinámicamente después de iniciar la aplicación. Para este propósito, he definido una interfaz IToolStripPopulator
:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
se inyecta una implementación de este en el MainForm
, y el método Load()
llamadas PopulateToolStrip()
con el ContextMenuStrip
y un controlador se define en el formulario. Las dependencias del usuario solo están relacionadas con la obtención de los datos que se utilizarán para los elementos del menú.
Esta abstracción ha funcionado bien mediante algunos pasos evolutivos, pero ya no es suficiente cuando necesito más de un controlador de eventos, p. porque estoy creando varios grupos diferentes de elementos de menú, aún ocultos detrás de una sola interfaz IToolStripPopulator
porque el formulario no debería preocuparse por eso en absoluto.
Como ya he dicho, creo que sé lo que la estructura general debe ser como - Me cambió el nombre de la interfaz IToolStripPopulator
a algo más específico * y ha creado uno nuevo cuya PopulateToolStrip()
método no tiene un parámetro EventHandler
, que en cambio se inyecta en el objeto (también permite mucha más flexibilidad con respecto al número de manipuladores requeridos por una implementación, etc.). De esta manera, mi "principal" IToolStripPopulator
puede ser fácilmente un adaptador para cualquier cantidad específica.
Ahora, lo que no tengo claro es la forma en que debo resolver las dependencias de EventHandler. Creo que los manipuladores deberían definirse todos en el MainForm
, porque eso tiene todas las otras dependencias necesarias para reaccionar adecuadamente a los eventos del menú, y también "posee" el menú. Eso significaría que mis dependencias para objetos IToolStripPopulator
eventualmente inyectados en MainForm necesitarían tomar dependencias en el objeto MainForm
mismo utilizando Lazy<T>
.
Mi primer pensamiento fue definir una interfaz IClickHandlerSource
:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
Esto fue implementado por mi MainForm
, y mi aplicación específica IToolStripPopulator
tomó una dependencia de Lazy<IClickHandlerSource>
. Mientras esto funciona, es inflexible. Tendría que definir interfaces separadas para un número potencialmente creciente de controladores (que violan severamente el OCP con la clase MainForm
) o extender de forma continua IClickHandlerSource
(que viola principalmente al ISP). Tomar dependencias directas de los manejadores de eventos parece una buena idea para los consumidores, pero el cableado individual de los constructores a través de las propiedades de la instancia perezosa (o similar) parece bastante desordenado, si es posible.
Mi mejor apuesta actualmente parece ser la siguiente:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
La interfaz todavía sería ejecutado por MainForm
y se inyecta como un conjunto unitario perezoso, y EventHandlerType
habría una enumeración personalizada con los diferentes tipos que necesito. Esto todavía no sería muy OCP, pero razonablemente flexible. EventHandlerType
obviamente tendría un cambio para cada nuevo tipo de controlador de eventos, como lo haría la lógica de resolución en MainForm
, además del nuevo controlador de eventos en sí y la (probablemente) nueva implementación adicional escrita de IToolStripPopulator
.
O .... una aplicación separada de IEventHandlerSource
que (como el único objeto) realiza una dependencia de Lazy<MainForm>
y resuelve los EventHandlerType
opciones a los gestores específicos definidos en MainForm
?
Estoy tratando de pensar en una forma de realmente obtener los controladores de eventos fuera de MainForm
de una manera factible, pero no puede parecerlo en este momento.
¿Cuál es mi mejor opción aquí, proporcionando el acoplamiento más flojo y la resolución más elegante de los diferentes manejadores de eventos?
[* Sí, probablemente debería haber dejado el nombre por sí solo para cumplir realmente con OCP, pero se veía mejor de esa manera.]
leí su pregunta varias veces, pero me falta un poco de información. ¿Puedes mostrar más código? Por ejemplo, ¿cómo se ven los consumidores de 'IEventHandlerSource', y cómo se ve la implementación de' IEventHandlerSource', y cómo está todo esto registrado? – Steven