2010-03-01 12 views
7

Je me mouille les pieds avec DI/IoC et MEF en particulier.MEF et interface séparée conduit à "Interface pour chaque classe"

J'ai une application Web qui a deux types de parties (peut-être plus un jour) définies par des interfaces qui ont besoin d'accéder à l'ensemble de l'environnement. L'application a une liste avec des implémentations concrètes pour chaque type, composée par MEF.

L'environnement se compose de:

  • plusieurs référentiels
  • de demande d'application en cours
  • de moteur de rendu
  • moteur de navigation
  • ainsi que quelques classes utilitaires statiques

Comment puis-je mettre la définition de l'interface s dans un ensemble séparé et en même temps spécifier l'injection de l'environnement?

Évidemment, je ne peux pas simplement référencer l'assemblage principal parce que cela doit faire référence à l'ensemble de contrat et je ne peux pas créer une référence circulaire.

Il semble que j'ai besoin de créer une interface pour chacune des classes d'environnement, et leurs types disponibles au public et ainsi de suite ... Il doit y avoir une meilleure façon ?!

Peut-être que je manque aussi la plus grande faille évidente ici, si quelqu'un pouvait le signaler pour moi?

Répondre

10

Si vous voulez découpler vos abstractions de leurs implémentations (toujours un objectif valable), vous devez définir ces abstractions dans leur propre assemblage. Du point de vue de la mise en œuvre, il est facile à gérer, car vous avez besoin de référencer les abstractions pour les implémenter. Il n'y a pas moyen de contourner cela si vous utilisez MEF ou non, de sorte que ce qu'il a toujours été:

[Import(typeof(IFoo))] 
public class MyFoo : IFoo { } 

Cependant, comme vous le dites, cela signifie que vous ne pouvez pas référencer votre Composition racine de la bibliothèque d'abstraction . Cependant, c'est comme cela devrait être, parce que les abstractions ne devraient pas s'inquiéter de la manière dont elles sont composées. En d'autres termes, vous devez implémenter la composition des dépendances en dehors de la bibliothèque d'abstraction. Un bon candidat pour cela est l'exécutable lui-même, alors que vous conservez toutes vos implémentations concrètes dans une ou plusieurs bibliothèques.

La bibliothèque d'abstraction aura aucune référence, alors que les consommateurs et les implémenteurs devraient faire référence, donc un graphe de dépendance pourrait ressembler à ceci:

Composition Root --> Abstractions <-- Implementations 

Lorsque les flèches indiquent une référence.

+0

"Impossible de référencer votre Composition Root à partir de la bibliothèque d'abstraction" - C'est le but, mais aussi la source de ma confusion. Si mes abstractions ont une propriété de type "Engine", qui est définie et implémentée dans ma bibliothèque d'implémentation, ai-je besoin de créer une interface "IEngine" pour ce type dans la librairie d'abstraction? Maintenant, si j'ai plusieurs types dans le besoin de référence, chacun avec leurs propres dépendances, il faudrait que je les résume tous dans la bibliothèque d'abstraction, n'est-ce pas? – wagi

+2

Oui, c'est correct. Toutes ces interfaces supplémentaires peuvent sembler beaucoup sur overhead, mais chacun est en fait un ** Seam ** où vous découpler l'implémenteur du consommateur. Le résultat final est un système couplé plus lâche. Le bénéfice peut ne pas être immédiatement évident, mais une fois que vous commencez à expérimenter le pouvoir de consommer et exposer des abstractions au lieu de types concrets, vous ne voudrez plus jamais revenir :) –

+0

merci, donc ce que je pensais être trop, est en fait parfaitement bien et nécessaire! – wagi