Recentemente molte persone hanno adottato DI nei loro progetti (sto lavorando con il nucleo di aspnet). Il problema che ho è che DI trasforma il mio codice verso il paradigma procedurale. Ad esempio in modo OOP vorrei fare:
class Something
{
Something(Other object, Dependency dep); // created manually or by factory obj
DoStuff();
}
Tuttavia con DI non posso creare direttamente la classe Something, perché ho bisogno di soddisfare le dipendenze. Ora il mio codice è generalmente simile a questo:
class Something
{
Something(Dependency dep); // resolved from di container
DoStuff(Object obj); // executed manually
}
Di conseguenza i miei oggetti non hanno metodi, sono solo pacchetti di proprietà che vengono elaborati da diversi servizi. D'altra parte dovrei creare oggetti giganti con molte dipendenze solo per eseguire compiti semplici, che richiedono l'1% del grafico dell'oggetto creato.
Come risolvere il mio progetto? Questo approccio ha svantaggi evidenti, ad esempio non posso passare a Qualcosa in classe, perché ha bisogno di Object to DoStuff, quindi devo inserirlo in qualche altra classe. Ci sono molti altri problemi, come la funzionalità diffusa su molti file, le difficoltà nell'implementazione della sicurezza (perché è possibile richiedere il servizio "interno" da DI) o l'incapsulamento (l'oggetto deve avere tutte le proprietà pubbliche perché sono manipolate dalla classe esterna.
Modifica: Piccolo esempio per una migliore illustrazione:
Api scriverei prima di DI:
class ShoppingCartFactory {
ShoppingCart Create(id);
}
// encapsulates cart logic
class ShoppingCart {
// internal dependencies passed to cart from factory
ShoppingCart(DeliveryLoader, ItemMetadataLaoder);
// methods encapsulation functionality
Modify(item, quantity);
Save();
Empty();
GetDeliveryOptions(); // loads possible transports from db
LoadItemMetadata(); // loads prices, availability etc. for items
// public properties
ImmutableList<CartItem> items; // immutable list of items
Delivery selectedDelivery; // transport selected by client
}
Quando il cliente fa clic sulle opzioni di consegna del carrello acquisti vengono visualizzate solo una volta e le richieste successive non ne hanno bisogno. Pertanto con questo approccio devo creare la dipendenza ShoppingCartDeliveryCreator per ogni richiesta.
Quindi, invece, devo scrivere qualcosa del genere:
// instead of having properties on cart Object now I have 3 separate classes
// in previous example user of api had no idea how cart works inside
// now he needs to find all classes associated with cart
// also service class needs to take id in each method
// or needs some method like 'Contextualize(id)'
class ShoppingCartService {
// executes logic on db
ShoppingCart Read(id);
ShoppingCart Modify(id, item, quenatity);
ShoppingCart Empty(id);
ShoppingCart Save(id, shoppingCart);
}
class ShoppingCartDeliveryCreator (...)
class ShoppingCartItemMetadataLoader (...)
// no logic
class ShoppingCart {
List<CartItem> items; // cannot be immutable, because Service needs to manipulate it
Delivery selectedDelivery; // same
}
Non puoi fare nulla con la classe ShoppingCart, hai sempre bisogno di uno dei servizi. Anche come ha sottolineato Derek Elkins
One of the consequences of systematically using Dependency Injection is that your class hierarchy becomes completely flat.
Non sono sicuro che questa sia una buona cosa. Ho fatto molte ricerche ed esperimenti, tuttavia non sono convinto di questo stile di programmazione. Per avere un'idea di come funziona qualcosa Devi esaminare tutto quel codice, indovinare cosa sta facendo e quindi potresti avere un'idea sottile di come funziona. Con il vecchio esempio potevi semplicemente guardare sulla classe e vedresti tutte le opzioni, oppure puoi controllare tutte le classi che prendono ShoppingCart.