2011-01-26 2 views
5

J'essaie de réévaluer notre architecture n-couche et j'aimerais avoir quelques suggestions basées sur vos expériences. Voici notre conception typique n-couche .NET (parfois n-tier).Conception de couche métier/service n-couche

Project.UI 
Project.Services 
Project.Business 
Project.Model 
Project.DataAccess 

DataAccess se compose généralement de Entity Framework 4 et Repository classes. Je tente de suivre le concept Aggregate Root afin d'éviter d'avoir un référentiel pour la table, plus facile à dire qu'à faire dans mon expérience. J'ai tendance à avoir une correspondance d'environ 70% entre les dépôts et les tables.

Le modèle se compose généralement de mes entités Entity Framework 4, j'utilise avec succès les entités EF Self-Tracking.

Business est ce que je lutte avec le plus. J'ai généralement une classe Manager pour chaque Repository. Cette classe contiendra des méthodes telles que .Add() qui effectuera une validation métier avant de les transférer vers repository.Add().

Services, typiquement je ne mettrai en œuvre que si en fait je cherche à créer une solution basée sur le service Web. Cette couche sera chargée de marshaler les demandes/réponses entre les DTO et les entités. Et surtout fournir l'interface plus coarse grained. Par exemple, un TradingService.SubmitTrade(), qui est vraiment un facade pour une transaction commerciale qui pourrait inclure AccountManager.ValidateCash(), OrderManager.SubmitOrder(), etc.

Préoccupations
Ma couche d'affaires est très entité centré, c'est vraiment le lien entre les entités et le référentiel, avec validation entre les deux. J'ai vu de nombreuses conceptions où le Service Layer est ce qui contient une référence aux dépôts (en ignorant par essence la "couche de gestion"). En substance, il sert le même but que ma couche d'affaires, il effectue la validation, mais sa responsabilité (et son nom) est un niveau plus élevé, une transaction commerciale plus grossière. En utilisant l'exemple ci-dessus, TradingService.submitTrade() ne délèguera pas à des classes de business manager, il interrogera lui-même les dépôts nécessaires, effectuera toutes les validations, etc.

J'aime mon design dans le sens où je peux réutiliser une entreprise méthode de couche dans plusieurs appels de service, mais je déteste le fait que pour chaque référentiel, j'ai un gestionnaire de couche de gestion correspondant, ce qui crée des tonnes de travail supplémentaire. Peut-être que la solution est un type différent de regroupement au niveau de la couche Business? Par exemple, combinez des classes Manager individuelles telles que PhoneManager et EmailManager (notez que j'ai les entités Phone et Email) dans une classe Logical Manager telle que ContactsManager (notez que je n'ai pas de type d'entité "Contact"). Avec des méthodes telles que ContactManager.GetPhones() et ContactManager.GetEmail(), etc.

Je suppose plus que tout que je me demande comment les autres organisent et délèguent des responsabilités, qu'ils aient la couche de service, la couche de gestion, les deux, etc. Ce qui contient la référence de contexte ORM, etc.

Répondre

2

J'ai tendance à faire ce que vous avez décrit à la fin de vos préoccupations, et au niveau de la couche de gestion, regroupez les choses dans des gestionnaires qui ont plus de sens logique d'un point de vue commercial.

En utilisant les contacts par exemple, je n'aurais certainement pas PhoneManager ou EmailManager. "ContactsManager" est un regroupement plus utile pour moi, accomplissant à peu près la même chose seulement avec beaucoup moins de gestionnaires à traiter. D'un point de vue commercial, les numéros de téléphone et les courriels ne sont que de petits morceaux d'un Contact. Juste parce qu'ils ont leurs propres tables et entités ne signifie pas qu'ils ont besoin de leur propre gestionnaire. Cela ne signifie pas que vous ne pouvez pas les réutiliser.Si vous avez besoin de travailler avec des adresses e-mail à plusieurs endroits, ContactsManager peut avoir les méthodes appropriées. Ce que nous avons tendance à avoir dans notre environnement est une couche base de données/entité, puis une couche métier qui se trouve sur le serveur et gère les règles métier et la logique métier. Cette couche de gestion est exposée en tant que service via le WCF au client (ou du moins, ce qui est pertinent pour les clients). Il semble que vous sachiez déjà ce que vous voulez faire, donc je vous suggère de faire un peu de travail de prototypage et de voir comment cela fonctionne pour vous. :)

+0

Avez-vous déjà eu un appel de service qui couvre plusieurs classes de gestionnaire d'entreprise? En d'autres termes, votre interface de service pourrait être encore plus grossière que les chefs d'entreprise. Par exemple, ContactService.CreateUser(), déléguera (servira de façade) à UserManager.CreateUser() et ContactManager.AddEmail(), et ContactManager.AddPhone(), etc. Même si nous avons regroupé la logique liée au courrier électronique et au téléphone dans ContactsManager , il n'y a rien de mal à avoir PhoneRepository et EmailRepository. Il me semble que les dépôts ne peuvent pas être "logiques" comme les gestionnaires. – e36M3

+0

Rarement, mais c'est arrivé. Je préfère garder le plus de logique possible dans la couche de gestion, car elle est disponible si quelqu'un vient me voir plus tard et souhaite qu'une page Web fasse exactement les mêmes choses que le service (et oui, cela arrive). La page Web peut appeler la même logique de couche de gestion que le service, plutôt que d'appeler le service (ils sont sur le même serveur dans mon cas). Donc ce que je ferais dans un cas comme celui-ci est d'avoir une méthode de gestion d'entreprise qui peut elle-même utiliser d'autres chefs d'entreprise. J'essaie de l'éviter sauf quand il y a un réel gain de simplicité. – Tridus

+0

Je sais ce que vous voulez dire, j'utilise DI pour créer mes gestionnaires pour leur fournir les dépôts requis via le constructeur. Un gestionnaire qui crée un autre gestionnaire exigerait que les gestionnaires connaissent le conteneur d'ID. Cependant, sans cela, il semble parfois que je duplique la logique en copiant et collant. Par exemple DataEntryManager.EnterPrice() et FileManager.UploadPriceFile(). Vous pouvez imaginer qu'après avoir analysé le "fichier des prix", nous aurions dû insérer des prix. Je peux dupliquer une partie de cette logique ou avoir FileManager réutiliser DataEntryManager. – e36M3

Questions connexes