Question

Je suis un grand fan de NTiers pour mes choix de développement, il ne marche pas de cours correspond à chaque scénario.

Je travaille actuellement sur un nouveau projet et je suis en train d'avoir un jeu avec la façon dont je l'habitude de travailler, et d'essayer de voir si je peux le nettoyer. Comme je l'ai été un garçon très mauvais et ai mettre trop de code dans la couche de présentation.

Ma structure normale de la couche d'affaires est ce (vue de base de celui-ci):

  • Business
    • Services
      • FooComponent
        • FooHelpers
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • BahWorkflows
    • Utilitaires
      • commune
      • ExceptionHandlers
      • Importateurs
      • etc ...

Maintenant, avec ce qui précède j'ai un excellent accès directement enregistrer un objet Foo et un objet Bah! Par l'intermédiaire de leurs assistants respectifs.

Les XXXHelpers me donnent accès à sauvegarder, éditer et charger les objets respectifs, mais où dois-je mettre la logique pour enregistrer des objets avec des objets enfant.

Par exemple:

Nous avons les objets ci-dessous (pas de très bons objets que je connais)

  • employé
  • EmployeeDetails
  • EmployeeMembership
  • EmployeeProfile

Actuellement, je construirait ces tous dans la couche de présentation et de les transmettre ensuite à leurs aides, je me sens cela est faux, je pense que les données doivent être transmises à un seul point au-dessus de la présentation dans la couche d'affaires une place et réglait il.

Mais je suis un peu d'une perte à l'endroit où je mettrais cette logique et ce qu'il faut appeler le secteur, serait-il passer sous Utilities EmployeeManager ou quelque chose comme ça?

Que feriez-vous? et je sais que tout cela est la préférence.

Une présentation plus détaillée

Les flux de travail contiennent tous les appels directement au DataRepository par exemple:

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

Et puis l'accès des fournisseurs d'aides aux flux de travail:

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

est de réduire la duplication de code, comme vous pouvez avoir un appel dans le flux de travail getBySomeProperty puis plusieurs appels dans l'aide qui pourrait faire d'autres opérations et le retour des données de différentes façons, un mauvais exemple serait publique GetByIdAsc et GetByIdDesc

En séparant les appels vers le modèle de données en utilisant le DataRepository, cela signifie qu'il serait possible d'échanger sur le modèle d'une autre instance (qui était la pensée), mais ProviderHelper n'a pas été divisé il est donc pas interchangable, comme il est à EF, malheureusement, coder en dur. Je ne l'intention de changer la technologie d'accès, mais à l'avenir il pourrait y avoir quelque chose de mieux ou juste quelque chose que tous les enfants de frais utilisent maintenant que je pourrais vouloir mettre en œuvre à la place.

projectName.Core

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

projectName.Presenation

(dépend de ce que l'appel de l'application est)

projectName.web
projectName.mvc
projectName.admin

Les projets de test

projectName.Business.Tests
projectName.Data.Test
Était-ce utile?

La solution

1 pour une question intéressante.

Alors, le problème que vous décrivez est assez commun - je prendrais une approche différente - d'abord avec les niveaux logiques et d'autre part avec les espaces de noms de services publics et aide, que je vais essayer et facteur complètement - Je vais vous dire pourquoi dans une seconde.

Mais d'abord, mon approche préférée ici est l'architecture d'entreprise assez commune que je vais essayer de mettre en évidence en bref, mais il y a beaucoup plus de profondeur là-bas. Il nécessite des changements radicaux dans la pensée - en utilisant le framework NHibernate ou Entité pour vous permettre d'interroger votre modèle d'objet directement et laissez l'affaire ORM avec des choses comme la cartographie vers et à partir de la base de données et les relations de chargement paresseux etc. Faire cela vous permettra de mettre en œuvre tous votre logique métier dans un modèle de domaine.

D'abord les niveaux (ou des projets dans votre solution);

YourApplication.Domain

Le modèle de domaine - les objets représentant votre espace de problème. Ce sont des objets anciens CLR simples avec tout votre logique métier clé. C'est là vos objets par exemple vivraient, et leurs relations seraient représentées sous forme de collections. Il n'y a rien dans cette couche qui traite de la persistance etc, il est juste des objets.

YourApplication.Data

cours du référentiel - ce sont des classes qui traitent d'obtenir la racine globale (s) de votre modèle de domaine.

Par exemple, il est peu probable que dans vos classes exemples que vous voulez regarder EmployeeDetails sans regarder aussi employé (une hypothèse que je sais, mais vous obtenez l'essentiel - les lignes de facture est un meilleur exemple, vous obtiendrez généralement à la facture des lignes par l'intermédiaire d'une facture plutôt que de les charger de façon indépendante). En tant que tel, les cours du référentiel, dont vous avez une classe par racine globale sera responsable de l'obtention des entités initiales de la base de données en utilisant l'ORM en question, la mise en œuvre des stratégies de requête (comme la pagination ou tri) et en retournant la racine globale au consommateur. Le dépôt consommerait le contexte de données actif courant (ISession dans NHibernate) -. Comment cette session est créée dépend de quel type d'application que vous construisez

YourApplication.Workflow

  • pourrait aussi appeler YourApplication.Services, mais cela peut être confondu avec les services Web
  • Ce niveau est tout au sujet des opérations liées entre elles, atomiques complexes -. Plutôt que d'avoir un tas de choses à appeler dans votre niveau de présentation, et donc d'augmenter le couplage, vous pouvez envelopper ces opérations dans les flux de travail ou des services
  • Il est possible que vous pourriez faire sans que cela dans de nombreuses applications.

D'autres niveaux dépendent alors de votre architecture et l'application que vous implémentez.

YourApplication.YourChosenPresentationTier

Si vous utilisez des services Web pour distribuer vos niveaux, alors vous créer des contrats DTO qui représentent seulement les données que vous exposons entre le domaine et les consommateurs. Vous définiriez assembleurs qui saura comment déplacer les données dans et hors de ces contrats du domaine (vous n'envoyer des objets de domaine sur le fil!)

Dans cette situation, et vous créez également le client, vous consommerait les opérations et les contrats données définies ci-dessus dans votre couche de présentation, contraignant probablement aux DTO directement comme chaque DTO doit être vue spécifique.

Si vous avez pas besoin de distribuer vos niveaux, se souvenant de la première règle d'architectures distribuées est ne distribue pas, alors vous consommer les flux de travail / services et dépôts directement dans asp.net, mvc, WPF, WinForms, etc.

Que seulement les feuilles où les contextes de données sont établis. Dans une application Web, chaque demande est généralement assez autonome, donc une demande scope contexte est le meilleur. Cela signifie que le contexte et la connexion est établie au début de la demande et disposée à l'extrémité. Il est trivial pour obtenir votre cHosen IoC / cadre d'injection de dépendance aux composants configure par demande pour vous.

Dans une application de bureau, WPF ou WinForms, vous auriez un contexte par formulaire. Cela garantit que les modifications apportées à des entités de domaine dans une boîte de dialogue d'édition qui mettent à jour le modèle, mais ne permettent pas à la base de données (par exemple: Annuler a été sélectionné). Ne pas interférer avec d'autres contextes ou pire finissent par être accidentellement persisté

injection de dépendance

Tout ce qui précède serait défini comme interfaces d'abord, avec les mises en œuvre concrètes réalisées grâce à un cadre d'injection COI et la dépendance (ma préférence est le château de Windsor). Cela vous permet d'isoler, maquettes et tests unitaires niveaux individuels indépendamment et dans une grande demande, l'injection de dépendance est un épargnant de vie!

Les espaces de noms

Enfin, la raison pour laquelle je perdrais l'espace de noms helpers est, dans le modèle ci-dessus, vous ne les avez besoin, mais aussi, comme les espaces de noms de services publics qu'ils offrent aux développeurs paresseux une excuse pour ne pas penser à où un morceau de code logique est assis. MyApp.Helpers. * Et MyApp.Utility. * Signifie simplement que si j'ai un code, dire un gestionnaire d'exception qui appartient peut-être logiquement au sein MyApp.Data.Repositories.Customers (peut-être est un ref client n'est pas unique exception), un paresseux développeur peut simplement placer dans MyApp.Utility.CustomerRefNotUniqueException sans vraiment avoir à y penser.

Si vous avez un code de type cadre commun que vous devez conclure, ajouter un projet MyApp.Framework et namespaces pertinents. Si Vous êtes en train d'ajouter un nouveau modèle de liaison, il mis en MyApp.Framework.Mvc, si elle est une fonctionnalité de journalisation commune, il mis en MyApp.Framework.Logging et ainsi de suite. Dans la plupart des cas, il ne devrait pas y avoir aucun besoin d'introduire un espace de noms de services publics ou des aides.

Emballez

Alors que qu'effleurer la surface - l'espoir qu'il est d'un peu d'aide. Voici comment je développe aujourd'hui le logiciel, et je l'ai intentionnellement essayé d'être bref - si je peux donner des détails sur les détails, laissez-moi savoir. La dernière chose à dire sur ce morceau est opiniâtres ci-dessus est pour le développement à grande échelle assez grande - si vous écrivez notepad la version 2 ou un annuaire téléphonique d'entreprise, ce qui précède est probablement totale surpuissant !!!

Vive Tony

Autres conseils

Il y a un schéma agréable et une description sur cette page au sujet de la mise en page de l'application, alhtough regarde plus bas l'article l'application isnt divisé en couches physiques (séparé projet) - Entity Framework POCO dépôt

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