业务逻辑层和数据访问层:循环依赖

时间:2009-01-19 16:02:49

标签: c# design-patterns architecture

我有一点架构问题。在我的项目中,我有一个业务逻辑层(BLL),其中包含我的所有业务规则,模型和接口的OO API。每个对象都有像getById这样的静态方法,它们返回所述对象的实例。每个对象也有像save和delete这样的方法。这是非常简单的OO代码。

现在我有一个DataAccess层(DAL),包含在一个单独的命名空间中,对于每个BLL对象,我有一个DataClass或“Repository”,它执行getById和save命令。所以在某种程度上,BLL save和getById方法是围绕DataClass方法的薄层。

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

为了让DataClasses返回BLL对象,他们需要知道BLL。所以现在我们有:

GUI ---> BLL< ----> DAL

DataFactory只返回实现接口的对象,因此我可以隐藏“OracleNewsItemRepository”之类的实现细节。

但是现在对于自从我开始面向对象编程以来一直困扰着我的事情。在我目前的解决方案中,BLL和DAL都需要相互了解。这是循环依赖关系,最佳做法是避免循环依赖关系。另外,我只想公开接口(和我的DataFactory),而不是我的类。这可以通过将DAL层放在单独的Assembly中来完成。这是有道理的。但是,Visual Studio不允许两个程序集相互引用。另一个问题是:C# internal access modifiers

不知怎的,我认为我的整个数据访问模式错了。感觉就像我正在使用DataMappers等其他东西来卷积ActiveRecord模式。我花了很多时间在Martin Fowler的网站上,但这些模式被描述得非常通用,并用非常抽象的UML图表来说明。

他们没有解决我的问题。也许我有点肛门,而且没有“完美的数据访问模式”这样的东西。我现在所做的事情似乎并不严重。但是我现在怎么做,似乎不在......

有什么想法吗?

8 个答案:

答案 0 :(得分:12)

我认为您的数据访问模式很好。你没有做的是将你的BLL耦合到OracleDAL。您正在耦合到DAL接口。绝对需要一定程度的耦合,否则你永远无法做任何事情。

我假设您的DataFactory和INewsItemRepository类存在于DAL层之外。以下是我的解决方案组织方式的示例。我不使用ActiveRecord,所以这可能不适合你。

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

OracleData (Project)
  Data
    Oracle Repository Implementations

SqlData (Project)
  Data
    Sql Repository Implementations

UI (Project)

希望这有帮助。

答案 1 :(得分:11)

在我看来:

数据访问层(DAL)应使用以下操作对POCO(普通旧CLR对象)进行操作:SaveNewsItem ( NewsItemDAO newsItemDAO )。 POCO是您的DAO(数据访问对象)。

业务层应该包含将数据访问对象(DAO)转换为富业务对象的逻辑,这可能只是DAO加上一些操作以及任何装饰/丰富。

DAL应该完全不了解业务逻辑层。从理论上讲,它应该可以从任何客户端调用。例如,如果您想从应用程序中分离DAL并将其部署为通过WCF公开自己的单独服务,该怎么办?

如上所述,DAL操作,例如, BO应该通过接口访问SaveNewsItem,可能是通过依赖注入/ IoC。

答案 2 :(得分:5)

您可以使用接口/依赖注入来解决您的问题。

您的业务层(BL)包含(可能不止一个)DAL需要实现的数据访问(DA)接口。 DAL项目具有对BL的项目引用,以便它们可以吐出业务对象(BO)并实现DA接口。

您的BO可以调用DataFactory,它可以通过依赖注入或反射来实例化DA对象。

我在工作中的许多应用程序中使用了这种模式(基于Web和智能客户端),并且它的工作非常好。

答案 3 :(得分:3)

现在有点旧了,但也许您应该考虑将pocos /接口放在另一个程序集中。

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

这里没有循环引用。

答案 4 :(得分:2)

为了清楚起见,我喜欢将业务模型和业务逻辑视为两个独立的层。您的业​​务模型是您的POCO(普通旧CLR对象)。您的业​​务逻辑层将负责使用您的业务模型和DAL接口执行验证,事务等,这些接口可以通过多种方式连接(Spring,Castle或您自己的本地IoC容器)。

使用业务模型在DAL中实现零依赖关系的好方法是使用已构建的对象关系映射框架(ORM),例如NHibernate(我最喜欢的ORM框架的无耻插件)。

答案 5 :(得分:2)

IceHeat,@ Claig Wilson的例子最有意义,其可能源于这篇文章:http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx

这是值得一读并解决域驱动的开发,它解决了您在这里遇到的问题。我建议任何人,即使你不给猴子NHibernate这篇文章很棒。

答案 6 :(得分:1)

我会从BLL(域模型)中删除任何Get()和Save()方法..这就是我要做的事情

GUI将要求Repository通过id获取域对象..一旦GUI具有域对象,您可以将其导航到其他对象。这样,Domain层不需要了解有关存储库的任何信息。

在内部存储库中,您可以返回懒惰加载或完全加载对象对象图的域对象..这将取决于您的需要..

以下是关于同一主题的好文章...... Reconstituting objects

阅读Deyan Petrov关于如何使用动态代理的评论

答案 7 :(得分:0)

DAL必须是抽象的,因此它必须只包含与后端数据库交互的普通ADO.NET对象,例如连接DataAdapter,DataReader等。 有了这些,您可以在您的Biz层中引用DAL,当涉及到具有一点抽象的实体时,您可以解决所有问题,例如,如果您有客户类,您可以创建一个abstaractoin客户类来实现与DAL交互的基本操作,如保存,更新和检索数据,以及在继承抽象类的另一个类中覆盖基类方法实现,以满足您的Biz验证等。