sto costruendo un'applicazione WinForms con un'interfaccia utente che consiste solo di un NotifyIcon
e la sua dinamica popolato ContextMenuStrip
. C'è un MainForm
per tenere insieme l'applicazione, ma non è mai visibile.CIO: Cablaggio dipendenze da gestori di eventi
Ho deciso di costruire questo il più SOLAMENTE possibile (utilizzando Autofac per gestire il grafico dell'oggetto) e sono piuttosto soddisfatto del mio successo, soprattutto andando molto d'accordo anche con la parte O. Con l'estensione che sto attualmente implementando sembra che ho scoperto un difetto nel mio design e ho bisogno di rimodellarlo un po '; Penso che conosca il modo in cui devo andare, ma sono un po 'oscuro su come definire esattamente le dipendenze.
Come accennato in precedenza, il menu viene compilato in parte in modo dinamico dopo l'avvio dell'applicazione. A questo scopo, ho definito un IToolStripPopulator
interfaccia:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
Un'implementazione di questo viene iniettato nel MainForm
, e il metodo Load()
chiama PopulateToolStrip()
con il ContextMenuStrip
e un gestore definito nella forma. Le dipendenze del populatore sono solo legate all'ottenimento dei dati da utilizzare per le voci di menu.
Questa astrazione ha funzionato bene attraverso alcuni passaggi evolutivi ma non è più sufficiente quando ho bisogno di più di un gestore di eventi, ad es. perché sto creando diversi gruppi di voci di menu - ancora nascosti dietro una singola interfaccia IToolStripPopulator
perché il modulo non dovrebbe preoccuparsi affatto di quello.
Come ho detto, credo di sapere quale sia la struttura generale dovrebbe essere come - ho rinominato l'interfaccia IToolStripPopulator
a qualcosa di più specifico * e ha creato uno nuovo la cui PopulateToolStrip()
metodo non prende un parametro EventHandler
, che viene invece iniettato l'oggetto (che consente anche molta più flessibilità per quanto riguarda il numero di gestori richiesti da un'implementazione, ecc.). In questo modo il mio "primo" IToolStripPopulator
può essere facilmente un adattatore per un numero qualsiasi di quelli specifici.
Ora quello che non sono chiaro è il modo in cui dovrei risolvere le dipendenze di EventHandler. Penso che i gestori dovrebbero essere tutti definiti nel MainForm
, perché questo ha tutte le altre dipendenze necessarie per reagire correttamente agli eventi del menu, e anche "possiede" il menu. Ciò significherebbe che le mie dipendenze per gli oggetti IToolStripPopulator
eventualmente iniettati nel MainForm avrebbero bisogno di assumere dipendenze sull'oggetto MainForm
utilizzando Lazy<T>
.
Il mio primo pensiero è stato la definizione di un IClickHandlerSource
interfaccia:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
Questo è stato realizzato dal mio MainForm
, e la mia specifica IToolStripPopulator
implementazione ha una dipendenza da Lazy<IClickHandlerSource>
. Mentre questo funziona, è inflessibile. Dovrei definire interfacce separate per un numero potenzialmente crescente di gestori (violando gravemente l'OCP con la classe MainForm
) o estendere continuamente IClickHandlerSource
(in particolare violando ISP). Le dipendenze dirette dei gestori di eventi sembrano una buona idea da parte dei consumatori, ma il cablaggio individuale dei costruttori tramite proprietà di istanza lazy (o simili) sembra piuttosto complicato, se possibile.
La mia scommessa migliore attualmente sembra essere questo:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
L'interfaccia sarebbe ancora essere implementata da MainForm
e iniettata come Singleton pigro, e EventHandlerType
sarebbe un enum personalizzato con i diversi tipi di cui ho bisogno. Ciò non sarebbe ancora molto conforme agli OCP, ma ragionevolmente flessibile. EventHandlerType
avrebbe ovviamente una modifica per ogni nuovo tipo di gestore di eventi, come pure la logica di risoluzione in MainForm
, oltre al nuovo gestore di eventi stesso e all'implementazione aggiuntiva (probabilmente) di nuova scrittura di IToolStripPopulator
.
O .... un'implementazione separata di IEventHandlerSource
che (come l'unico oggetto) batte una dipendenza da Lazy<MainForm>
e risolve i EventHandlerType
opzioni ai gestori specifici definiti in MainForm
?
Sto provando a pensare a un modo per ottenere effettivamente i gestori di eventi da MainForm
in modo fattibile, ma non riesco a sembrare al momento.
Qual è la mia opzione migliore qui, fornendo l'accoppiamento più flessibile e la più elegante risoluzione dei diversi gestori di eventi?
[* Sì, probabilmente dovuto lasciare il solo nome di rispettare davvero con OCP, ma sembrava meglio così.]
ho letto la tua domanda più volte, ma mi manca un po 'di informazioni. Puoi mostrare più codice? Ad esempio, come appaiono i consumatori di "IEventHandlerSource" e come appare l'implementazione di "IEventHandlerSource" e in che modo tutto questo è stato registrato? – Steven