Injection de dépendance: à quel moment suis-je autorisé à créer un nouvel objet?

13

Je refactorise une application PHP , et j'essaie de faire autant d' injection de dépendance (DI) que possible.

Je sens que j'ai une bonne compréhension de son fonctionnement, et je peux certainement voir mes cours devenir beaucoup plus légers et plus robustes.

Je refactorise pour pouvoir injecter une dépendance plutôt que de créer un nouvel objet dans la classe, mais à un moment donné, je vais devoir créer des objets, c'est-à-dire utiliser le newmot clé redouté .

Le problème que je rencontre maintenant est à quel point puis-je réellement créer de nouveaux objets? On dirait que je vais me retrouver dans une classe de haut niveau, créant des tas de nouveaux objets car il n'y a nulle part où aller. Cela ne va pas.

J'ai lu certains blogs qui utilisent des classes d'usine pour créer tous les objets, puis vous injectez l'usine dans d'autres classes. Vous pouvez alors appeler les méthodes d'usine et l'usine crée le nouvel objet pour vous.

Ce qui m'inquiète, c'est que mes cours d'usine vont être newgratuits pour tous! Je suppose que cela peut être OK car ce sont des classes d'usine, mais y a-t-il des règles à respecter lors de l'utilisation d'un modèle d'usine et d'une DI, ou est-ce que je vais loin de la marque ici?

Gaz_Edge
la source
Je recommande l'IoC pour les services et les politiques. Pour les classes de modèle ou d'aide, j'utiliserais simplement new. Bien sûr, il y a quelques points d'entrée où vous devez appeler dans le conteneur IoC, mais il ne devrait pas y en avoir beaucoup. En règle générale, vous configurez l'IoC une fois, puis demandez qu'une classe soit résolue par demande. Dans le cas de MVC, c'est généralement le contrôleur.
CodesInChaos
La classe de niveau supérieur que vous mentionnez fait partie de la racine de composition. C'est loin d'être faux.
Facio Ratio

Réponses:

12

Après un peu de recherche sur ce sujet, il semble que (comme mentionné dans un commentaire ci-dessus), la classe de niveau supérieur dont je parlais s'appelle la racine de composition .

Il semble en effet être la solution acceptée pour ajouter la création de tous les objets au sein de cette racine de composition (ou référencer un conteneur IoC à partir d'ici).

Ma préoccupation initiale à ce sujet était que cette classe de haut niveau finirait par être un peu en désordre. C'est vrai dans une certaine mesure, mais les avantages pèsent les inconvénients. Par exemple, je peux voir que la lisibilité, la testabilité et la maintenabilité de toutes mes autres classes se sont améliorées.

La classe de niveau supérieur peut être un peu désordonnée, jonchée de new, set_property()mais je dois dire que je préfère en fait avoir tout ce code en un seul endroit plutôt que dispersé dans toutes les autres classes

Une autre page utile pour discuter des performances de cette méthode ici

Gaz_Edge
la source
1
+1 parce que je n'avais jamais entendu parler de «Composition Root» auparavant.
c_maker
2

Une classe Factory aura newsaupoudré tout au long. Ce serait créer n'importe quel objet que vous demandez et probablement les dépendances de cet objet. Puisque le travail des usines est d'instancier le bon objet pour vous, avoir newdans cette classe n'est pas une mauvaise chose.

DI est pour que vous ayez une conception à couplage lâche. Vous pouvez apporter des modifications à votre application en modifiant la dépendance fournie à chaque objet. Rendre votre application flexible, extensible et facile à tester.

Au niveau supérieur, vous disposerez d'un code qui instanciera quelques usines, établira des connexions aux services et enverra une réponse. Il aura une quantité importante d' newappels statiques pour instancier les objets nécessaires à votre application. Ce serait là que cela appartient.

Schleis
la source
-2

Mes deux cents ici:

Je refactorise une application php et j'essaie de faire autant d'injection de dépendances que possible

Vous ne précisez pas si vous utilisez un framework d'injection de dépendances. Je pense que vous devriez certainement. Utilisez quelque chose qui vous offre les fonctionnalités dont vous avez besoin: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .

Le problème que je rencontre maintenant est à quel point puis-je réellement créer de nouveaux objets? On dirait que je vais me retrouver dans une classe de haut niveau, créant des tas de nouveaux objets car il n'y a nulle part où aller. Cela ne va pas.

Vous utilisez normalement la configuration ou un point central pour l'instanciation des objets initiaux qui composent votre application. Le conteneur créera les objets pour vous.

Vous accédez ensuite aux objets (services, fournisseurs, contrôleurs ...) via le conteneur IoC. Il créera de manière transparente un objet pour vous si nécessaire, ou vous donnera une référence à l'instance existante appropriée.

Bien sûr, dans votre implémentation particulière d'objets, vous pouvez instancier d'autres objets sur lesquels vous n'avez pas besoin de DI (structures de données, types personnalisés, etc.), mais c'est une programmation normale.

J'ai lu certains blogs qui utilisent des classes d'usine pour créer tous les objets, puis vous injectez l'usine dans d'autres classes. Vous pouvez alors appeler les méthodes d'usine et l'usine crée le nouvel objet pour vous.

Normalement, vous utilisez une fabrique si vous souhaitez que le framework IoC instancie certains objets IoC via vos usines (cela est nécessaire lorsque l'instanciation d'un objet particulier nécessite un travail supplémentaire). Si vous pouvez simplement créer vos objets avec "new Object ()" et définir certaines propriétés, vous ne voulez pas nécessairement utiliser un modèle Factory.

En d'autres termes, je dirais que l'utilisation d'un modèle Factory pour une classe ou un groupe de classes dépend de la façon dont vous souhaitez modéliser ces classes, et non de l'utilisation de DI (sauf si votre implémentation DI nécessite explicitement des usines, ce qui est inhabituel).

Vous configurez également votre infrastructure IoC pour utiliser une usine lorsque vous utilisez une bibliothèque tierce qui nécessite déjà l'utilisation d'une usine. Dans ce cas, vous n'avez aucun contrôle à ce sujet et vous devez dire à votre conteneur IoC: "hé, quand je demande une de ces interfaces, vous devez utiliser cette usine pour me fournir une instance appropriée".

Ce qui m'inquiète, c'est que mes cours d'usine vont devenir un nouveau cours gratuit pour tous! Je suppose que cela peut être correct car ce sont des classes d'usine, mais y a-t-il des règles à respecter lors de l'utilisation du modèle d'usine et de la DI, ou suis-je loin de la marque ici.

Dans ce cas, il semble que vous n'ayez pas besoin d'utiliser des modèles Factory pour ces objets / services / contrôleurs / quoi que ce soit, et vous pouvez simplement configurer votre IoC pour instancier avec "new" la classe appropriée et injecter tout le reste.

J'espère que ça aide.

jjmontes
la source
merci pour la réponse, mais le conteneur IoC est sûrement la «classe de niveau supérieur» à laquelle je faisais référence. Si je peux seulement créer des objets là-dedans, ça va être un vrai bordel.
Gaz_Edge
4
doing DI manually beats the whole purpose of using an Inversion of Control container- Si vous entendez par là "... qui centralise vos dépendances dans un fichier de configuration", alors vous avez raison, car c'est tout ce qu'un conteneur IoC fait vraiment. Le véritable objectif de DI est le découplage, et vous pouvez le faire en fournissant vos dépendances dans une méthode constructeur. Vous n'avez pas du tout besoin d'un framework DI pour cela.
Robert Harvey
mmm vous ne créez pas d'objets, vous leur demandez le conteneur IoC (de n'importe où vous devez), ou vous utilisez l'injection de champ / argument afin que vos classes soient automatiquement injectées les classes appropriées, créées toujours par le conteneur IoC.
jjmontes
1
Je conviens que vous avez besoin d'un cadre pour de très grandes applications. De nombreuses applications ne sont pas si grandes et ne bénéficient pas de la complexité supplémentaire de l'utilisation d'un cadre DI.
Robert Harvey
2
Je n'ai pas dit que c'était le cas. J'ai simplement dit que vous n'avez pas besoin d'un conteneur DI pour le faire.
Robert Harvey