Couche logique métier et couche D'accès aux données: dépendance circulaire

J'ai un petit problème D'Architecture. Dans mon projet, j'ai une couche de logique métier (BLL) qui contient toutes mes règles métier, modèles et API OO pour l'interface. Chaque objet a des méthodes statiques comme getById qui renvoient une instance de cet objet. Chaque objet a également des méthodes telles que save et, delete. C'est un code oo très simple.

Maintenant, j'ai une couche DataAccess (dal), contenue dans un espace de noms séparé, pour chaque objet BLL, j'ai une DataClass ou" Repository " qui exécute les commandes getbyid et save. Donc, d'une certaine manière, les méthodes BLL save et getById sont une couche mince autour des méthodes de classe de données.

public static NewsItem GetByID(int id)
{
       return DataFactory.GetNewsItemRepository().GetNewsItemById(id);
}

Pour que les DataClasses renvoient des objets BLL, elles doivent connaître le BLL. alors maintenant, nous avons:

GUI - - - > BLL DAL

DataFactory ne renvoie que les objets qui implémentent une Interface, donc je peux masquer les détails d'implémentation comme "OracleNewsItemRepository".

Mais maintenant pour la chose qui m'embête depuis que je commencé la programmation Orientée Objet. Dans ma solution actuelle, BLL et le DAL doivent se connaître. Il s'agit d'une dépendance circulaire, et il est recommandé d'éviter les dépendances circulaires. Aussi, je veux seulement exposer les interfaces (et mon DataFactory) et pas mes classes. Cela peut être fait en plaçant la couche DAL dans un assemblage séparé. Ce qui aurait du sens. Cependant, Visual Studio ne permet pas à deux assemblys de se référer l'un à l'autre. Une autre question à ce sujet: c # accès interne modificateurs

D'une manière ou d'une autre, je pense que j'ai mal tout mon modèle d'accès aux données. Il se sent comme je convolute le modèle ActiveRecord avec d'autres choses comme DataMappers. J'ai passé beaucoup de temps sur le site de Martin Fowler, mais ces modèles sont décrits très génériques et sont illustrés par un diagramme UML très abstrait.

Ils ne résolvent pas mon problème. Peut-être que je suis un peu anal, et il n'y a pas de "modèle d'accès aux données parfait". Et ce que je fais maintenant ne semble pas terriblement mal. Mais comment je fais les choses maintenant, semble éteint ...

Des idées?

23
demandé sur Community 2009-01-19 19:02:49

8 réponses

Je pense que votre modèle d'accès aux données est bien. Ce que vous ne faites pas, c'est coupler votre BLL à L'OracleDAL. Vous êtes couplé aux interfaces DAL. Un certain couplage est absolument nécessaire ou vous ne pourriez jamais rien faire.

Je suppose que votre DataFactory et les classes INewsItemRepository existent en dehors de votre couche DAL. Ce qui suit est un exemple de la façon dont mes solutions sont organisées. Je n'utilise pas ActiveRecord, donc cela peut ne pas vous convenir parfaitement.

Core (Project)
  Domain
    Business Entities
  Data
    Repository Interfaces
    **Your DataFactory**

OracleData (Project)
  Data
    Oracle Repository Implementations

SqlData (Project)
  Data
    Sql Repository Implementations

UI (Project)

Espoir cela aide.

12
répondu Craig Wilson 2009-01-19 18:17:18

, À mon avis:

La couche D'accès aux données (DAL) doit fonctionner sur des poco (objets CLR anciens) en utilisant des opérations telles que: SaveNewsItem ( NewsItemDAO newsItemDAO ). Les poco sont vos Dao (objets D'accès aux données).

La couche métier doit contenir la logique pour convertir un objet D'accès aux données (DAO) en un objet métier riche, qui est probablement juste le DAO plus certaines opérations ainsi que toute décoration/enrichissement.

Le DAL ne devrait avoir aucune connaissance de la couche de logique métier. Il devrait, en théorie, être capable d'être appelé de n'importe quel client. Par exemple, que faire si vous vouliez séparer le DAL de l'application et le déployer en tant que service séparé s'exposant via WCF?

Comme mentionné, les opérations DAL, par exemple SaveNewsItem devraient être accessibles par le BO via des interfaces, peut-être via dependency injection/IoC.

11
répondu ng5000 2009-01-20 10:27:05

Vous pouvez utiliser l'injection d'interfaces/dépendances pour résoudre votre problème.

Votre couche métier (BL) contient les interfaces D'accès aux données (DA) que le DAL (éventuellement plusieurs) doit implémenter. Les projets DAL ont des références de projet à BL afin qu'ils puissent cracher des objets métier (BOs) et implémenter les interfaces DA.

Votre BOs peut appeler DataFactory, qui peut instancier un objet DA via une injection de dépendance ou une réflexion.

J'ai utilisé ce modèle dans beaucoup de nos applications ici au travail (à la fois sur le web et smart-client), et il fonctionne à merveille.

5
répondu user53564 2009-01-19 17:34:20

C'est un peu vieux maintenant mais peut-être que vous auriez dû envisager de mettre les pocos/interfaces dans un autre assemblage.

Project.Data references Project.Entities
Project.BL references Project.Entities and Project.Data
Project.UI references Project.Entities and Project.BL

Ici, il n'y a pas de références circulaires.

3
répondu Chaos 2012-02-25 23:56:15

Juste pour être clair, j'aime penser à un modèle D'affaires et à une logique métier comme deux couches distinctes. Votre modèle d'affaires sont vos poco (Plain old CLR objects). Votre couche de logique métier serait responsable d'effectuer des validations, des transactions, etc. en utilisant à la fois votre modèle d'affaires et une interface à votre DAL qui pourrait être câblée de plusieurs façons (Spring, Castle ou votre propre conteneur IoC).

Un bon moyen d'atteindre zéro dépendance dans votre DAL avec votre entreprise le modèle consiste à utiliser un framework ORM (object relation mapping framework) déjà construit tel que NHibernate (un plug sans vergogne pour mon framework ORM préféré).

2
répondu Trent 2009-01-19 17:50:49

IceHeat, l'exemple de @Craig Wilson a le plus de sens et son probablement dérivé de cet article: http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx .

Cela vaut bien une lecture et aborde le développement piloté par le domaine qui résout les problèmes auxquels vous êtes confrontés ici. Je le recommande à tout le monde, même si vous ne donnez pas un singe à propos de NHibernate c'est un excellent article.

2
répondu Owen 2009-01-19 18:33:31

Je supprimerais toute méthode Get () et Save () de votre BLL (modèle de domaine).. voici ce que je ferais

L'interface graphique demandera au référentiel d'obtenir l'objet de domaine par id.. et une fois que L'interface graphique a l'objet de domaine, vous pouvez le Naviguer pour atteindre d'autres objets.. De cette façon, la couche de domaine n'a pas besoin de savoir quoi que ce soit sur les référentiels..

Dans le référentiel, vous pouvez renvoyer un objet de domaine qui se charge paresseusement ou charger complètement le graphe d'objet objet.. cela dépendrait de vos besoins..

Voici un bon d'écrire sur le même sujet...Reconstituer des objets

Lisez le commentaire de Deyan Petrov sur l'utilisation du proxy dynamique

1
répondu StackUnderflow 2009-01-19 19:17:39

DAL doit être abstrait, donc il doit contenir uniquement ADO.NET objets qui interagissent avec la base de données backend par exemple connexion DataAdapter, DataReader et ainsi de suite. Avec cela, vous pouvez référencer DAL dans votre couche Biz, et quand il s'agit de vos entités avec un peu d'abstraction, vous pouvez résoudre tous vos problèmes, par exemple si vous avez une classe client, vous pouvez créer une classe client abstaractoin qui implémente les opérations de base pour interagir avec DAL comme enregistrer, mettre à jour et récupérer des données et dans une autre classe qui hérite de la classe abstraction, remplacez l'implémentation des méthodes de classe de base pour répondre à votre validation Biz, etc.

0
répondu Abdullah BaMusa 2009-01-19 18:31:52