L'utilisation de l'injection de dépendances et d'un conteneur d'inversion de contrôle doit-elle supprimer toutes les occurrences du new
mot clé " " de votre code?
En d'autres termes, chaque objet / dépendance, quelle que soit sa simplicité ou sa durée de vie, doit-il être "enregistré" dans votre conteneur IoC et injecté dans la méthode / classe qui doit les utiliser?
Si non, où tracez-vous la ligne entre les dépendances / objets enregistrés dans le conteneur IoC, par rapport à ce qui est créé "en ligne" comme référence concrète, via le new
mot-clé?
Réponses:
Évitez le dogme. Faites ce qui vous semble bien.
Je préfère utiliser "nouveau" pour les structures de données qui n'ont aucun comportement.
Si la classe a un comportement, je regarde alors la portée de ce comportement. S'il est apatride et n'a pas de dépendances, je penche vers "nouveau". Je ne commence à refactoriser vers DI que lorsque j'ai besoin d'ajouter une dépendance aux ressources avec état (comme une base de données ou un fichier), ou à d'autres classes avec de telles ressources.
la source
new
dépendance 'ed dans mon propre code qui a incité ma question. C'était une classe simple sans fonctionnalité ni "comportement" en soi, seulement des propriétés simples.Dans mon livre , je fais la distinction entre les dépendances stables et volatiles . Il est très important d'utiliser DI avec des dépendances volatiles, mais souvent vous pouvez obtenir un couplage encore plus lâche en extrayant et en injectant également des dépendances stables.
Gardez à l'esprit que l'application de DI ne doit pas reposer sur un conteneur DI . Dans le cas où l' ID du pauvre est utilisé, aucun
new
mot-clé n'est supprimé - ils sont simplement déplacés vers la racine de composition .Certaines personnes préfèrent en fait la DI de Pauvre aux conteneurs de DI. Le coût de maintenance peut être plus élevé, mais vous obtenez en retour une sécurité au moment de la compilation. Comme j'ai récemment entendu Dan North dire: "
new
est le nouveaunew
" :)Ce que cela signifie est simplement qu'au lieu d'implémenter la racine de composition avec un conteneur DI, il contiendrait simplement un tas d'
new
instructions imbriquées .la source
"nouveau" n'est pas un mot clé interdit. Mes règles personnelles:
Tous les "services" (j'appelle un service une classe conçue pour fournir une ou plusieurs méthodes liées à une et une seule chose; par exemple: accéder à la base de données, récupérer / mettre à jour les données relatives à un domaine donné) sont enregistrés dans le conteneur IOC. Aucune classe ne devrait avoir à décider comment obtenir la mise en œuvre d'un service donné dont elle a besoin. Par conséquent, chaque fois que vous devez utiliser un service existant, vous devez configurer votre classe et le conteneur IOC pour vous le fournir. Imaginez que vous ne savez pas comment fonctionne votre implémentation, il peut s'agir d'un service Web, peu vous importe.
Tous les beans ou modèles doivent être créés avec le mot-clé "new" ou avec une fabrique enregistrée par le CIO lorsque j'en ai besoin pour activer certaines propriétés par défaut. Il y a aussi le cas particulier des classes utilitaires ne contenant que des méthodes statiques (par exemple: un service utilitaire mathématique). S'ils sont totalement autonomes et n'ont besoin d'aucune connexion à une base de données ou d'un autre service enregistré auprès du CIO, je les laisse en dehors du CIO et ils doivent être appelés statiquement. Cependant, si l'une de ces classes doit utiliser un service enregistré auprès du CIO, je le change en classe singleton et l'enregistre dans le CIO.
la source
Je voudrais juste ajouter aux réponses existantes qui ont été soulevées Earler,
new
c'est parfaitement bien de créer des objets qui sont des objets de valeur pure (c'est-à-dire qui n'ont que des propriétés / getters / setters). Consultez le blog de test Google pour plus de détails.la source
new
éditéCela dépend clairement de la langue que vous utilisez. Si votre langage vous oblige à utiliser des objets pour représenter à la fois l'objet réel et les enregistrements (objet de valeur, structures), la réponse est très probablement non.
Parlant uniquement d'objets "réels", il n'y a rien de mal à créer explicitement une instance. Ce que vous devez cependant garder à l'esprit, c'est que toutes les classes doivent suivre le principe de la responsabilité unique. Il ne devrait pas être de la responsabilité d'une classe de choisir l'implémenteur d'un service sur lequel elle s'appuie. Cependant, il y a des classes qui ont la même responsabilité, c'est-à-dire de fournir des implémenteurs de certains services. Un IoC pourrait être une telle classe. En fait, tout type d’usine est une telle classe.
Donc, pour résumer: seules ces classes devraient instancier directement des objets, à qui revient la responsabilité de choisir les classes à instancier.
Vous pourriez trouver ces critères utiles: http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator
la source
Un mot: non.
Plus de mots: l'injection de dépendance est exactement cela. C'est un moyen par lequel vous introduisez des ressources dont un autre objet dépend, mais ne devrait pas connaître les détails complexes d'une autre source. L'utilisation de DI ne signifie pas que RIEN dans votre programme ne doit savoir comment créer un autre objet; en fait, je postule qu'il est hautement irréalisable pour un programme non trivial d'éviter complètement le "nouveau" mot clé (ou les alternatives basées sur la réflexion). Cependant, DI signifie que les objets qui ne devraient pas avoir à savoir comment créer des objets complexes qui nécessitent beaucoup de dépendances qui coupleront étroitement cet objet à l'autre, ne devraient pas avoir toutes ces connaissances étroitement couplées.
J'étudierais les deux principales théories de la conception de logiciels O / O, GRASP et SOLID. GRASP vous dira d'étudier le but de l'objet et vous demandera: "Cet objet devrait-il être responsable de la création de nouveaux objets de cet autre type? Cela fait-il partie de la" description du travail "de cet objet?" SOLID va encore plus loin: le «S» représente le «principe de responsabilité unique», qui stipule sans ambiguïté qu'un objet doit avoir un travail, et qu'il doit être le seul objet du programme qui effectue ce travail spécifique.
Donc, GRASP vous encourage généralement à regarder à travers vos classes existantes pour lesquelles créer ces nouveaux objets, et à en trouver une pour laquelle la tâche de créer cet objet correspond à ce que fait déjà l'objet, tout en maintenant votre niveau de "cohésion" souhaité. SOLID vous dira que la cohésion est la clé; la tâche de créer ces objets devrait être confiée à une fabrique qui devrait être injectée dans votre classe. Je pense que vous constaterez, à mesure que la complexité de votre programme continue de croître, que l'adhésion à l'une ou l'autre de ces méthodologies, avec une volonté de refactorisation, se traduira par des architectures très similaires.
la source