Uso dell'iniezione per servizi che contengono solo funzioni pure

3

Immagina di avere un servizio come questo:

class SomeService {
    // A random pure function that transforms the input
    // without doing any remote calls or any side effects
    function somePureFunction(inputNumber) {
        return inputNumber *2
    }
}

Ora lo stiamo usando registrandolo con un'iniezione di dipendenza e inserendolo in vari componenti (classi) in vari punti.

Non mi piace tale design, perché non vedo il punto di usare DI in questo caso e, invece, consiglio sempre di creare una classe statica Utils / Helper per tali metodi a cui è possibile accedere staticamente.

Fondamentalmente, sto cercando di trovare validi argomenti per cui una classe di helper statica è migliore in questo caso e apprezzerei molto altre opinioni su questo argomento.

    
posta eddyP23 16.11.2018 - 12:55
fonte

2 risposte

4

L'iniezione di dipendenza richiede un trade-off tra il disaccoppiamento di parti del codice a scapito di aumentarne la complessità attraverso la creazione di astrazioni. Quindi, come regola generale, l'aumento della complessità deve offrire vantaggi che superano i costi.

Iniettando dipendenze mutabili o con effetti collaterali, otteniamo evidenti benefici. Il codice diventa più facile da testare poiché questi effetti collaterali possono essere presi in giro. Controlliamo quali parti del sistema hanno accesso a quelle parti mutanti, rendendo il codice più pulito, più facile da capire e più facile da mantenere. L'aumento della complessità è facilmente neutralizzato da questi benefici.

Ma se una dipendenza è pura, non otteniamo alcuno di questi benefici, tuttavia continuiamo ad aumentare i costi di complessità. Vorresti iniettare Math.PI (o l'equivalente) o accedervi direttamente? È una costante, quindi non ci sarebbe alcun vantaggio nel farlo; può essere reso accessibile a livello globale. Ma sicuramente lo stesso vale per Math.Max() ? È completamente deterministico. Non ci sarebbe alcun vantaggio a deriderlo; nessun vantaggio nello swapparlo per un'altra implementazione di Max . Quindi, di nuovo, è un costo di complessità senza guadagno. Così anche dovrebbe essere accessibile a livello globale.

Se la resa di Math.Max() globalmente accessibile ha senso. Allo stesso modo, rendere il tuo somePureFunction accessibile a livello globale ha anche senso. L'iniezione di nuovo rende il codice più complesso senza ulteriori vantaggi.

Ovviamente, è importante sottolineare "puro" qui. Se la tua funzione in qualche modo non è deterministica, ha effetti collaterali o muta in qualche modo i parametri passati, non è pura e quindi non dovrebbe essere accessibile a livello globale. Iniettarli. Non iniettare pure funzioni.

    
risposta data 16.11.2018 - 13:13
fonte
5

L'iniezione di dipendenza ha senso quando si desidera cambiare quella dipendenza. Ad esempio, potresti voler prendere in giro una dipendenza per il test. Per una funzione pura, dovresti chiederti:

  • Questa funzione è un'utilità che si mantiene universalmente, ad es. %codice%? In tal caso, evitare la complessità dell'iniezione di dipendenza sembra assolutamente soddisfacente.

  • O questa funzione fornisce alcuni servizi che contengono la logica aziendale, ad es. %codice%? Quindi, potresti voler cambiare il servizio tramite l'integrazione delle dipendenze.

La differenza tra questi casi non è sempre evidente. A volte viene utilizzata un'utilità pura come Math.Max() in cui la scelta di utilizzare quella funzione dovrebbe già essere configurabile, ad es. come calculateSalesTax() . Ma nella maggior parte dei casi, non è necessario farlo subito. Se si sta lavorando su un'applicazione, è possibile scrivere un semplice codice ora e un refactoring per utilizzare DI in un secondo momento, se necessario. Tuttavia, un'API che viene utilizzata da altre persone potrebbe trarre vantaggio dall'aggiunta anticipata di questi punti di estensione in modo da non interrompere la compatibilità con le versioni precedenti in futuro.

    
risposta data 16.11.2018 - 15:43
fonte

Leggi altre domande sui tag