Va bene usare il localizzatore di servizi per le dipendenze diffuse? [chiuso]

1

Rispettiamo rigorosamente l'inversione del controllo nella nostra base di codice, ma questo crea costruttori infernali (sì, lo so che significa che le nostre classi non sono abbastanza coerenti, questo è un work in progress). Il fatto è che a volte queste dipendenze sono piuttosto sciocche come un wrapper DateTime per abilitare la gestione delle date, o il logger o un wrapper TaskFactory che non sono direttamente correlati all'attività della classe e non credo che richiedano un'introduzione esplicita. / p>

Potremmo ridurre il carico sui nostri operatori utilizzando un localizzatore di servizi per quegli articoli che sono passati in tutto il sistema? Quali sarebbero gli svantaggi?

    
posta Ziv 29.11.2015 - 13:39
fonte

4 risposte

3

La domanda è, hai davvero bisogno delle dipendenze a quel livello?

Cose come un datetime wrapper possono essere utilizzate in due modi: o hai bisogno di ottenere una data da assegnare a qualcosa (l'ordine è stato piazzato 'now'), o hai bisogno di un po 'di tempo per eseguire un'azione (prendimi tutti gli ordini in sospeso che sono stati piazzati sette giorni prima di "adesso"). Nel primo caso, la tua dipendenza dal wrapper è assoluta perché la classe ne ha bisogno. Nel secondo caso, puoi rielaborare il tuo metodo in modo che impieghi qualsiasi datetime e la logica di "sette giorni prima di ora" sia spinta in alto, riducendo le dipendenze della tua classe.

Per quanto riguarda la registrazione, dipende ancora dalla tua applicazione. Se si registrano eccezioni, è probabile che si abbia solo la dipendenza dalle classi di registrazione in un codice di primo livello. Se si sta effettuando la registrazione come parte di una funzione di controllo, è possibile avere un'implementazione in cui gli eventi vengono generati dagli oggetti ma solo registrati in un'unica posizione, riducendo ancora la dipendenza dalla registrazione.

La ragione principale per evitare i locatori di servizi è perché nascondono le dipendenze della tua classe. Ciò rende più difficile per te progettare buone classi (SOLID), renderle più difficili da testare e trasformare gli errori in fase di compilazione per le dipendenze basate sul costruttore in errori di runtime per le classi basate su Service Locator.

    
risposta data 29.11.2015 - 14:06
fonte
1

Presumo che quando si dice un "wrapper DateTime" ciò che si intende veramente è un'interfaccia "Orologio" che può essere interrogata per il valore DateTime che gli umani occasionalmente percepiscono come "ora".

Anch'io ho riscontrato il problema di dover passare molto le mie dipendenze, e l'ho risolto con un adattamento universale leggero di Domain Driven Design invece di un Localizzatore di servizi. (Non mi piacciono i localizzatori di servizio proprio perché, come ha sottolineato JDT, possono rimandare un errore in fase di compilazione a un errore di runtime.)

L'idea è questa:

Ogni oggetto appartiene idealmente a un dominio . In questo caso, è chiamato oggetto di quel dominio.

Un dominio è la fabbrica esclusiva dei suoi soggetti. Nessun altro può creare un'istanza di un soggetto. Ciò a sua volta significa che tutti i soggetti costruttori sono nascosti al mondo esterno. (Pacchetto privato in java.)

Ogni soggetto riceve un riferimento al dominio a cui appartiene come primo parametro del costruttore. (Questo è analogo al modo in cui ogni metodo di un oggetto riceve il puntatore this come il suo primo parametro (nascosto).)

Ogni soggetto che ha bisogno di un qualche tipo di servizio lo ottiene dal proprio dominio tramite una proprietà. (GetXYZ regolare (), nessuna ricerca della mappa.)

Il dominio può offrire direttamente un servizio (come in myDomain.getGradientSaturator() ) o indirettamente (come in myDomain.getSplineDomain().getReticulator() .)

Idealmente, i soggetti sono visibili al codice esterno (codice al di fuori del namespace o del pacchetto del loro dominio) tramite interfacce, non come classi concrete. (Ma questo è irrilevante per questa discussione.)

I domini ricevono le loro dipendenze come parametri del costruttore.

Nessuno ha bisogno di interrogare alcun repository per i servizi, nessun enorme elenco di dipendenze viene passato né ai costruttori né ai metodi factory, (eccetto forse ai costruttori di domini, che sono rari) e la disponibilità di tutti i servizi è garantita (quindi per parlare *) dal compilatore.

Tuttavia, in vari luoghi in cui vengono costruite gerarchie di domini, vengono forniti tutti i servizi necessari, quindi ognuno di essi può essere sostituito con una simulazione.

In mancanza di un termine migliore, sto chiamando questa Programmazione orientata al soggetto per il momento.

(*) per così dire, a meno che tu non faccia qualcosa di sciocco, come passare null a un costruttore che si aspettava un GradientSaturator .

    
risposta data 02.12.2015 - 02:50
fonte
1

L'iniezione delle dipendenze risolve un problema particolare, tuttavia, poiché la trovi, aggiunge complessità. Non è qualcosa che dovresti sempre fare per tutto perché è sempre "buono", in quanto può effettivamente aggiungere un sovraccarico per determinati tipi di manutenzione. Ad esempio, una modifica in cui si aggiunge un requisito per utilizzare una dipendenza in un metodo richiede che il codice venga modificato per aggiungere un campo di iniezione al costruttore e la modifica in cui si utilizza la dipendenza stessa.

L'iniezione di dipendenza ti consente di cambiarlo più tardi. Per qualcosa come una data, se non si prevede in nessuna situazione che il sistema di gestione della data cambierà (il che è praticamente il caso per qualsiasi linguaggio di programmazione maturo che fornisce la gestione della data), aggiungere l'iniezione di dipendenza per questa funzione ha un costo e non ti dà nulla Quindi non farlo. Se lo fai, stai violando il principio di non averne bisogno.

Quindi, se non hai bisogno della flessibilità che DI ti offre per alcuni dei servizi che stai praticando, basta portarli fuori, utilizzare un localizzatore di servizi o anche (horror) una dipendenza diretta. È un giudizio: se in seguito ti rendi conto di aver bisogno di quella flessibilità, le moderne piattaforme di sviluppo del codice ti permetteranno di aggiungerlo senza troppi problemi.

    
risposta data 02.12.2015 - 12:13
fonte
0

Cosa succederebbe se decidessi che la Classe A ha bisogno di un logger diverso (per esempio) rispetto alla Classe B? O ancora più difficile, se l'istanza 1 della Classe A ha bisogno di un logger diverso dall'istanza 2 della Classe A?

Potresti non avere questo requisito ora, ma nella funzione potresti averlo. Forse vuoi specifiche classi o istanze per accedere a file diversi o per utilizzare librerie di registrazione completamente diverse.

Queste preoccupazioni potrebbero anche essere valide per le altre dipendenze che si desidera ottenere dal localizzatore di servizio.

Non puoi risolvere questo problema se stai utilizzando il Service Locator perché il servizio Il localizzatore limita la componibilità . D'altra parte, se si iniettano le dipendenze, si ha il pieno potere di comporre i propri oggetti in ogni modo che si desidera.

    
risposta data 01.12.2015 - 23:56
fonte