63 votes

Dois-je avoir un assemblage séparé pour les interfaces ?

Nous avons actuellement tout à fait un peu de classes dans un projet, et chacune de ces classes implémentent une interface, surtout pour les DI raisons.

Maintenant, mon sentiment personnel est que ces interfaces doivent être mis dans un autre espace de noms au sein de la même assemblée (nous avons donc un MyCompany.CoolApp.DataAccess de l'assemblée, et dans ce qu'il y a un Interfaces d'espace de noms de donner des MyCompany.CoolApp.DataAccess.Interfaces).

Cependant, quelqu'un a suggéré que ces interfaces doivent être réellement dans leur propre assemblée. Et ma question est: sont - ils de droite? Je peux voir qu'il y a certains avantages (par exemple. d'autres projets aurez seulement besoin de consommer de l'interface de l'assemblée), mais à la fin de la journée, l'ensemble de ces assemblées allez avoir besoin d'être chargé. Il me semble aussi qu'il pourrait être un peu plus complexe problème de déploiement de, que Visual Studio ne tirez pas automatiquement la mise en œuvre de l'assemblage dans le dossier bin.

Sont-il des lignes directrices de pratiques exemplaires pour cela?

EDIT:

Que mon point de vue un peu plus clair: Nous avons déjà séparé de l'INTERFACE utilisateur, DataAccess, modèle de données et d'autres choses dans les différentes assemblées. Nous pouvons également en train d'échanger nos de mise en œuvre avec une mise en œuvre différente, sans douleur, comme nous la carte de la mise en œuvre de la classe de l'interface à l'aide de l'Unité (CIO cadre). Je tiens à souligner que nous n'avons jamais écrire deux implémentations d'une même interface, sauf pour des raisons de polymorphisme et de créer des objets fantaisie pour les tests unitaires. Donc, nous ne sommes pas actuellement de "swap" une mise en œuvre, sauf dans les tests unitaires.

Le seul inconvénient que je vois à avoir l'interface de la même assemblée que la mise en œuvre est que l'ensemble de l'assemblée (y compris le solde non utilisé de la mise en œuvre), aura été chargé.

Je peux, cependant, voir le point de les avoir dans une autre assemblée qui signifie que les développeurs n'ont pas accidentellement "nouvelle" la mise en œuvre de la classe plutôt que de l'avoir créé à l'aide du CIO wrapper.

Un point que je n'ai pas compris à partir des réponses est le problème de déploiement. Si je suis juste en fonction de l'interface assemblées, je vais avoir un quelque chose comme la structure suivante:

MyCompany.MyApplication.WebUI
    References:
        MyCompany.MyApplication.Controllers.Interfaces
        MyCompany.MyApplication.Bindings.Interfaces
        etc...

Quand j'ai construit ce, les assemblées qui sont automatiquement placés dans le dossier bin sont ceux de l'interface assemblées. Cependant, mon type de mappings à l'unité de la carte d'interfaces différentes pour leurs implémentations réelles. Comment les assemblées qui contiennent mes implémentations à la fin dans le dossier bin?

34voto

Adam Houldsworth Points 38632

La pratique habituelle est de les placer dans leur propre assemblée, parce qu'alors un projet donné consommant ces interfaces ne nécessite pas dur de référence pour la mise en œuvre de ces interfaces. En théorie, cela signifie que vous pouvez échanger à la mise en œuvre avec peu ou pas de douleur.

La difficulté vient quand vous voulez créer une instance de l'interface - mais DI cadres de résoudre ce problème.

Dans un scénario de déploiement, si vous avez modifié la mise en œuvre vous pourrait, en théorie, il vous suffit de déployer cette DLL unique - laissant ainsi à, disons, l'INTERFACE utilisateur et de l'interface Dll seul. Si vous avez compilé votre interfaces et la mise en œuvre, ensemble, vous pourriez alors avoir besoin de redéployer l'IU DLL...

Un autre avantage est propre à la ségrégation de votre code - avoir une des interfaces (ou bibliothèque partagée) DLL explicitement les états à toute l'équipe de développement où placer les nouveaux types etc.

Je ne sais pas si il y a de meilleures pratiques pour ou contre, la chose la plus importante est sans doute que dans le code, vous êtes toujours consommer les interfaces et de ne jamais laisser aucun code de fuite à l'aide de la mise en œuvre.

23voto

David_001 Points 2825

Les réponses semblent dire que le fait de mettre les interfaces dans leur propre assemblée est l'pratiques "habituelles". Je ne suis pas d'accord avec mettre indépendants des interfaces dans un "partagé" assemblée commune, de sorte que cela implique, j'ai besoin d'avoir 1 interface de montage pour chaque "mise en œuvre" de l'assemblée.

Cependant, en y réfléchissant davantage, je ne peux pas penser à beaucoup trop d'exemples dans le monde de cette pratique (par exemple. ne log4net ou NUnit fournir de l'interface publique assemblées afin que les consommateurs peuvent décider ensuite sur les différentes implémentations? Si oui, quels sont les autres de la mise en œuvre de nunit puis-je l'utiliser?). Passer par la recherche grâce à google, j'ai trouvé un certain nombre de ressources.

11voto

Tim Lloyd Points 23571

Le modèle que j'ai suivi pour ce que j'appelle partagé types (et j'ai aussi utiliser DI) est une assemblée distincte qui contient les éléments suivants pour le niveau d'application de concepts (plutôt que des concepts communs qui vont dans la commune assemblées):

  1. Partagé interfaces.
  2. Otd.
  3. Des Exceptions.

De cette façon, les dépendances entre les clients et l'application de base des bibliothèques peuvent être gérés, que les clients ne peuvent pas prendre une dépendance sur une mise en œuvre concrète, soit directement, soit comme une conséquence de l'ajout d'un montage direct de référence et ensuite l'accès à tout public type.

J'ai alors d'un runtime type de design où j'ai mis ma DI conteneur au démarrage de l'application, ou le début d'une suite de tests unitaires. Dans ce sens, il y a une séparation claire entre les implémentations et comment je peux faire varier la via DI. Mon client modules n'ont jamais une référence directe à la réalité de bibliothèques de base, seul le "SharedTypes" de la bibliothèque.

La clé pour ma conception est d'avoir un moteur d'exécution courant de concept pour les clients (que ce soit une application WPF ou NUnit) qui définit les dépendances nécessaires c'est à dire des implémentations concrètes ou une sorte de simulacres\talons.

Si le ci-dessus partagé les types ne sont pas pris en compte, mais plutôt les clients d'ajouter une référence à l'assembly avec la mise en œuvre concrète, alors il est très facile pour les clients à utiliser les implémentations concrètes plutôt que les interfaces, à la fois évidente et non de manière évidente. Il est très facile de mettre graduellement fin avec couplage au fil du temps ce qui est quasi impossible de faire le tri, sans beaucoup d'efforts et surtout de temps.

Mise à jour

Pour clarifier un exemple de la façon dont les dépendances à la fin dans l'application cible.

Dans ma situation, j'ai un WPF application client. J'utilise Prism et l'Unité (pour DI) où important, Prism est utilisé pour l'application de la composition.

Avec Prism votre demande assemblée est juste une Coquille, implémentations réelles de la fonctionnalité réside dans "Module" assemblées (vous pouvez utiliser un ensemble distinct pour chaque Module conceptuel, mais ce n'est pas une obligation, j'ai l'un des Modules de l'assemblée ATM). Il est de la responsabilité de la coquille pour charger les Modules - la composition de ces Modules est de l'application. Les Modules utilisent le SharedTypes de l'assemblée, mais la coquille des références concrètes assemblées. Le moteur d'exécution type de design que j'ai discuté est responsable de l'initialisation de dépendances, et ceci est fait dans le Shell.

De cette manière, le module assemblages qui ont toutes les fonctionnalités ne dépendent pas des implémentations concrètes. Ils sont chargés par le shell qui trie les dépendances. La coquille des références concrètes assemblées, et c'est de cette façon qu'ils obtiennent dans le répertoire bin.

La Dépendance De L'Esquisse:

Shell.dll <-- Application
  --ModuleA.dll
  --ModuleB.dll
  --SharedTypes.dll
  --Core.dll
  --Common.dll + Unity.dll <-- RuntimeDI

ModuleA.dll
  --SharedTypes.dll
  --Common.dll + Unity.dll <-- RuntimeDI

ModuleB.dll
  --SharedTypes.dll
  --Common.dll + Unity.dll <-- RuntimeDI

SharedTypes.dll
  --...

1voto

Talha Yousuf Points 1

Je suis à la recherche d'System.Data.dll (4.0) dans l'explorateur d'Objets, et je vois qu'il est autonome en soi, avec non seulement des interfaces, mais toutes les classes instrumentales comme DataSet, DataTable, DataRow, DataColumn etc en elle. En outre, survolant la liste des espaces de noms qu'il détient comme Système.De Données, Système D'.Les données.Commune, Système D'.Configuration & System.Xml il suggère d'abord d'avoir des interfaces contenues dans leurs propres assemblées avec toutes les règles et le code de lieu de concert, et les deuxième et plus important encore, à ré-utiliser les mêmes espaces de noms à travers l'ensemble de l'application (ou le cadre) pour seggregate classes pratiquement ainsi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X