Question

Je commence tout juste avec DI & amp; tests unitaires et ont rencontré un problème qui, j'en suis sûr, est une évidence pour les développeurs plus expérimentés:

J'ai une classe appelée MessageManager qui reçoit des données et les enregistre dans une base de données. Au sein du même assemblage (projet dans Visual Studio), j'ai créé une interface de référentiel avec toutes les méthodes nécessaires pour accéder à la base de données. L’implémentation concrète de cette interface se trouve dans un assemblage séparé appelé DataAccess.

DataAccess a donc besoin d’une référence de projet à MessageManager pour connaître l’interface du référentiel. De plus, MessageManager a besoin d'une référence de projet à DataAccess pour que le client de MessageManager puisse injecter une implémentation concrète de l'interface de référentiel. Ceci est bien sûr interdit.

Je pourrais déplacer l'interface dans l'assemblage d'accès aux données, mais je pense que l'interface du référentiel est censée résider dans le même assemblage que le client qui l'utilise

Alors, qu'est-ce que j'ai mal fait?

Était-ce utile?

La solution

Utilisez-vous un Inversion of Control Container? Si oui, la réponse est simple.

L’ensemble A contient:

  • MessageManager
  • IRepository
  • ContainerA (add MessageManager)

L'assemblage B contient (et l'assembly de la référenceA):

  • Le référentiel implémente IRepository
  • ContainerB étend ContainerA (add Repository)

L'assembly C (ou B) démarrera l'application / ask le conteneur de MessageManager qui saura comment résoudre MessageManager et le référentiel IR.

Autres conseils

Vous devez séparer votre interface de l'un ou l'autre assemblage. Mettre l'interface avec le consommateur ou l'implémenteur va à l'encontre de l'objectif de l'interface.

Le but de l'interface est de vous permettre d'injecter n'importe quel objet qui implémente cette interface, qu'il s'agisse ou non du même assemblage auquel votre objet DataAccess appartient. D'autre part, vous devez autoriser MessageManager à utiliser cette interface sans qu'il soit nécessaire d'utiliser une implémentation concrète.

Placez votre interface dans un autre projet et le problème sera résolu.

Vous n'avez que deux choix: ajouter un assemblage pour tenir l'interface ou le déplacer dans l'assemblage DataAccess. Même si vous développez une architecture dans laquelle la classe DataAccess peut éventuellement être remplacée par un autre implémenteur (même dans un autre assemblage) de l'interface de référentiel, il n'y a aucune raison de l'exclure de l'assembly DataAccess.

Je pense que vous devriez déplacer l'interface de référentiel vers l'assembly DataAccess. Ensuite, DataAccess n'a plus besoin de faire référence à MessageManager.

Cependant, cela reste difficile à dire puisque je ne connais presque rien de votre architecture ...

Vous pouvez souvent résoudre les problèmes de référence circulaire en utilisant l'injection de setter au lieu d'injection de constructeur.

En pseudo-code:

Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);

L'inversion de dépendance est en jeu:

Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre d'abstractions. Les abstractions ne doivent pas dépendre des détails. Les détails devraient dépendre des abstractions.

L'abstraction dont dépendent les classes de l'assemblage DatAccess doit figurer dans un assemblage distinct de celui des classes DataAccess et de l'implémentation concrète de cette abstration (MessageManager).

Oui, c'est plus d'assemblages. Personnellement ce n'est pas un gros problème pour moi. Je ne vois pas un gros inconvénient dans les assemblées supplémentaires.

Vous pouvez conserver la structure actuelle (sans la dépendance de MessageManager à DataAccess à l'origine du problème), puis MessageManager charger dynamiquement l'implémentation concrète requise au moment de l'exécution à l'aide de . System.Reflection.Assembly classe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top