L'Injection de dépendance vs Emplacement de Service
Je suis actuellement en pesant les avantages et les inconvénients entre DI et SL. Cependant, j'ai trouvé moi-même dans la suite de catch 22 qui implique que je dois utiliser SL pour tout, et seulement injecter un conteneur IoC dans chaque classe.
DI Catch 22:
Certaines dépendances, à l'instar de Log4Net, il suffit de ne pas convenir à DI. J'appelle ces méta-dépendances et sentent qu'ils doivent être opaques pour le code appelant. Ma justification étant que si une simple classe " D " a été initialement mis en œuvre sans l'enregistrement, puis pousse à besoin de se connecter, alors dépendante des classes 'A', 'B' et 'C' doit maintenant en quelque sorte obtenir cette dépendance et de la transmettre à partir de " A " à " D " (en supposant que 'A' compose 'B', 'B' compose 'C', et ainsi de suite). Maintenant, nous avons apporté d'importantes modifications de code, juste parce que nous avons besoin de se connecter dans une classe.
Nous avons donc besoin d'un opaque mécanisme pour obtenir des méta-dépendances. Deux me viennent à l'esprit: Singleton et SL. L'ancien a connu des limites, principalement en ce qui concerne rigide de délimitation de l'étendue de ses capacités, au mieux, un Singleton utilisera un Résumé de l'Usine qui est stocké à la portée de l'application (c'est à dire. dans une variable statique). Cela permet une certaine souplesse, mais n'est pas parfait.
Une meilleure solution serait d'injecter un conteneur IoC dans de telles classes, et ensuite utiliser SL depuis l'intérieur de la classe pour résoudre ces méta-dépendances à partir du conteneur.
Donc catch 22: parce que la classe est maintenant injecté avec un conteneur IoC, alors pourquoi ne pas l'utiliser pour résoudre toutes les autres dépendances de trop?
J'apprécierais vos pensées 🙂
- Votre commentaire sur la nécessité de passer d'Une->B->C->D suggère que vous êtes confus au moment de l'exécution et le temps de création. Voir misko.hevery.com/2009/03/30/collaborator-vs-the-factory/...
- Grand commentaire WW, qui a honnêtement aidé à rectifier un gros blocage psychologique, j'ai eu re DI.
- À mon humble avis l'emplacement de service est pauvre homme d'inversion de contrôle, il vous donne une partie des avantages d'une bonne Cio, mais en n'étant pas explicite défaites beaucoup de ses avantages. L'injection de dépendance est où son à la.
Vous devez vous connecter pour publier un commentaire.
En utilisant le localisateur de service modèle va à l'encontre de l'un des principaux points de l'injection de dépendance. Le point de l'injection de dépendance est de rendre les dépendances explicites. Une fois que vous cachez-les dépendances en n'en faisant pas explicite des paramètres d'un constructeur, vous n'êtes plus à faire à part entière de l'injection de dépendances.
Ce sont tous les constructeurs pour une classe nommée
Foo
(défini sur le thème de la chanson de Johnny Cash):Mal:
Mal:
Mal:
Droite:
Seulement celui-ci rend la dépendance sur
Bar
explicite.Que pour l'enregistrement, il y a une bonne façon de le faire sans qu'il pénètre dans votre domaine de code (il ne devrait pas, mais si c'est le cas alors vous utiliser l'injection de dépendance de la période). Étonnamment, le Cio, les conteneurs peuvent aider avec ce problème. Début ici.
this.bar = bar;
au lieu dethis.Bar = bar;
Service Locator est un anti-modèle, pour des raisons parfaitement décrit à http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. En termes de connexion, vous pouvez considérer que comme une dépendance tout comme les autres, et de les injecter une abstraction par le constructeur ou des biens de l'injection.
La seule différence avec log4net, est qu'il nécessite que le type de l'appelant qui utilise le service. À l'aide de Ninject (ou tout autre contenant) Comment puis-je trouver le type qui demande le service? décrit comment vous pouvez résoudre ce problème (il utilise Ninject, mais est applicable à tout conteneur IoC).
Sinon, vous pourriez penser à l'enregistrement de manière transversale préoccupation, qui n'est pas appropriée à mélanger avec votre code de la logique métier, dans ce cas vous pouvez utiliser l'interception qui est fourni par de nombreux Cio conteneurs. http://msdn.microsoft.com/en-us/library/ff647107.aspx décrit à l'aide de l'interception à l'Unité.
Mon avis est que cela dépend. Parfois l'un est meilleur et parfois l'autre. Mais je dirais qu'en général je préfère DI. Il ya quelques raisons pour cela.
Lorsque la dépendance est injecté en quelque sorte en composant, il peut être considéré comme faisant partie de son interface. Ainsi, il est plus facile pour la composante de l'utilisateur à fournir ce avec des dépendances, parce qu'ils sont visibles. En cas de injectés SL ou Statique SL que les dépendances sont cachés et d'utilisation de la composante est un peu plus difficile.
Injecté avec des dépendances sont mieux pour les tests unitaires cause, vous pouvez tout simplement se moquer d'eux. Dans le cas de SL que vous avez à l'installation Locator + maquette dépendances de nouveau. Donc, c'est plus de travail.
Parfois de journalisation peut être mis en œuvre à l'aide de AOP, de sorte qu'il ne se mélange pas avec la logique métier.
Autrement, les options sont :
http://aabs.wordpress.com/2007/12/31/the-ambient-context-design-pattern-in-net/
Bien sûr, ce contexte doit être configurable, de sorte que vous pouvez utiliser stub/maquette pour les tests unitaires.
D'autres ont suggéré l'utilisation de AmbientContext, est de mettre la Date/Heure actuelle du fournisseur , de sorte que vous pouvez stub cours de test unitaire, et accélère le temps si vous le souhaitez.
J'ai utilisé Google Guice DI framework en Java, et découvert qu'il fait beaucoup plus que de rendre le test plus facile. Par exemple, j'avais besoin d'un journal séparé par application (pas de classe), avec la condition que tous mes bibliothèques de code utiliser l'enregistreur dans l'actuel contexte d'appel. L'injection de l'enregistreur de rendu cela possible. Certes, tout le code de la bibliothèque a besoin d'être modifié: l'enregistreur de données a été injecté dans les constructeurs. Au premier abord, j'ai résisté à cette approche parce que de toutes les modifications de codage requis; finalement j'ai réalisé que les modifications n'a eu de nombreux avantages:
Inutile de dire que je suis maintenant un grand fan de DI, et de l'utiliser pour tous, mais le plus trivial des applications.
Nous avons atterri sur un compromis: l'utilisation DI mais bundle de haut niveau de la dépendance à un objet en évitant de refactoring de l'enfer les dépendances de changement.
Dans l'exemple ci-dessous, nous pouvons ajouter à 'ServiceDependencies", sans avoir à refactoriser tous les dérivés de dépendances.
Exemple:
C'est à propos de la "Service Locator est un Anti-Modèle" par Mark Seeman.
J'ai peut-être mal ici. Mais j'ai juste pensé que je devais partager mes pensées aussi.
La méthode Process() pour OrderProcessor ne fait pas suivre le "Inversion de Contrôle" principe. Il rompt également le principe de Responsabilité Unique au niveau de la méthode. Pourquoi une méthode d'être concernés par l'instanciation de la
objets(par le biais des nouvelles ou de toute S. L. classe) dont il a besoin pour accomplir n'importe quoi.
Au lieu d'avoir la méthode Process() créer les objets le constructeur peut effectivement avoir des paramètres pour les objets respectifs(lire les dépendances) comme indiqué ci-dessous. Alors, COMMENT pouvons-un Service Locator être différent d'un autre CIO
conteneur. ET il va de l'aide dans les Tests Unitaires ainsi.
Je sais que cette question est un peu vieux, j'ai juste pensé que je voudrais donner à mon entrée.
En réalité, 9 fois sur 10, vous n'avez pas vraiment besoin SL et devrait s'appuyer sur DI. Cependant, il y a certains cas où vous devriez utiliser SL. Un domaine que je trouve moi-même à l'aide de SL (ou une variante, celle-ci) est dans le développement de jeux.
Un autre avantage de SL (à mon avis) est la possibilité de passer autour de
internal
classes.Ci-dessous est un exemple:
Comme vous pouvez le voir, l'utilisateur de la bibliothèque n'a aucune idée de cette méthode a été appelée, parce que nous n'avons pas DI, non pas que nous serions en mesure de toute façon.
Si l'exemple ne prend log4net comme la dépendance, alors il vous suffit pour ce faire:
Il n'y a pas de point d'injection de la dépendance comme log4net fournit granulaire de journalisation en prenant le type (ou une chaîne) comme paramètre.
Aussi, DI n'est pas en corrélation avec SL. A mon avis le but de ServiceLocator est pour résoudre les dépendances optionnelles.
Ex: Si le SL offre un ILog interface, je vais écrire la journalisation de la daa.
Je sais que les gens sont vraiment dire DI est la seule bonne CIO motif, mais je n'ai pas cette. Je vais essayer de vendre SL un peu. Je vais utiliser la nouvelle MVC framework pour vous montrer ce que je veux dire. Premier DI moteurs sont vraiment complexe. Ce que les gens vraiment dire quand ils disent DI, est d'utiliser un cadre de travail comme Unité, Ninject Autofac... que faire tout le levage lourd pour vous, où SL peut être aussi simple que de faire une usine de classe. Pour un petit rapide de ce projet est un moyen facile de faire du CIO, sans apprentissage tout un cadre pour une bonne DI, ils pourraient ne pas être si difficile à apprendre, mais encore.
Maintenant pour le problème que DI peut devenir. Je vais utiliser une citation de MVC Core docs.
"ASP.NET Core est conçu à partir du sol jusqu'à l'appui et à tirer parti de l'injection de dépendance." La plupart des gens disent que sur DI "les 99% de votre base de code devrait avoir aucune connaissance de votre conteneur IoC." Alors, pourquoi auraient-ils besoin de conception de sol si seulement 1% de code devrait être conscient, n'est-ce pas vieux MVC soutien DI? Eh bien c'est le grand problème de la DI cela dépend de DI. Tout en faisant travailler "COMME IL faut le FAIRE" prend beaucoup de travail. Si vous regardez la nouvelle Action d'Injection n'est-ce pas en fonction de DI si vous utilisez
[FromServices]
attribut. Maintenant DI les gens vont dire NON, vous sont censés pour aller avec les Usines pas ce genre de choses, mais comme vous pouvez le voir, pas même les gens faisant MVC fait droit. Le problème de la DI est visible dans les Filtres ainsi, regardez ce que vous devez faire pour obtenir des DI dans un filtreOù, si vous avez utilisé SL vous pourriez avoir fait cela avec var _logger = Localisateur.Get();. Et puis nous arrivons à la Vue. Avec tous il y a de la bonne volonté concernant DI ils avaient à utiliser SL pour la vue. la nouvelle syntaxe
@inject StatisticsService StatsService
est le même quevar StatsService = Locator.Get<StatisticsService>();
.La plupart annoncés partie de la DI est le test unitaire. Mais ce que les gens et de faire est tout simplement de le tester, il se moquer de services n'ayant pas de but ou d'avoir à câbler il DI moteur pour faire des tests réels. Et je sais que vous pouvez faire quelque chose de mal, mais les gens finissent par faire un SL localisateur même si ils ne savent pas ce que c'est. Où beaucoup de gens font des DI sans jamais de lire sur elle d'abord.
Mon plus gros problème avec le DI est que l'utilisateur de la classe doit être au courant du fonctionnement interne de la classe dans d'autres de l'utiliser.
SL peut être utilisé de la bonne manière et a quelques avantages en plus de sa simplicité.