C# 如何将业务层和数据层完全分离?

C# 如何将业务层和数据层完全分离?,c#,design-patterns,C#,Design Patterns,目前,我在应用程序的单个项目中表示我的业务层和数据层。我对这两组类的关注点进行了很好的分离。但是,我的数据层类将作为参数并返回我的业务对象。因此,我将使用类似的代码(请不要对这段代码过于挑剔,我的生产代码看起来不太像这样): //业务类片段 公共bool Save() { 如果(this.IsValid) { //DataProvider是实现IDataProvider接口的许多数据访问类之一。在类中的其他位置切换。这允许切换数据库提供程序、xml等。 DataProvider.Save(这个)

目前,我在应用程序的单个项目中表示我的业务层和数据层。我对这两组类的关注点进行了很好的分离。但是,我的数据层类将作为参数并返回我的业务对象。因此,我将使用类似的代码(请不要对这段代码过于挑剔,我的生产代码看起来不太像这样):

//业务类片段
公共bool Save()
{
如果(this.IsValid)
{
//DataProvider是实现IDataProvider接口的许多数据访问类之一。在类中的其他位置切换。这允许切换数据库提供程序、xml等。
DataProvider.Save(这个);
返回true;
}
返回false;
}
公共列表GetObjectsByCriteria(字符串条件)
{
返回DataProvider.GetMyBusinessObjectsByCriteria(条件);
}
我不希望我的业务类必须处理数据集,就像我喜欢让我的数据层类处理业务类一样

为了解决这个问题,我读了很多关于数据访问对象或数据传输对象的文章,但对于这些模式来说,这似乎是一个反模式的案例


我能做什么?如何优雅地实现应用程序这两个层的完全分离?

将持久性逻辑从业务对象中提取出来,并将它们放入数据仓库。它的工作原理类似于.NET中现有的适配器(OleDbDataAdapter)的工作原理。这样,您还将分离业务对象和持久性逻辑


您的客户机代码将更加冗长,但我认为这确实是真正分离层的最佳方式。

执行此操作的流行模式是Repository模式。在本例中,存储库使用集合语义充当门面,完全隐藏持久化数据所在的位置,无论是文件系统还是数据库。您可以实现它来访问数据,然后将数据映射到您想要使用的任何类型


您可以将域驱动设计作为您正在使用的活动记录模式的替代方案。

您应该看看DAO模式(数据访问对象)

最好是使用现成的DAO构造(弹簧加载)。看看

DAO不是反模式!将它们与Spring和泛型一起使用,您就不必在意;)

每一层之间都有连接!将它们完全分离意味着它们无法进行通信(因此它们是无用的)


使用基本的CRUD操作或动态查找程序,只要它有语义意义。

这是一个比如何将域模型与数据访问分离更普遍的问题。当您试图将应用程序逻辑与域模型、表示模型与应用程序逻辑等分离时,也会出现同样的问题

常见的解决方案是一种称为依赖项注入(DI)的技术。有些人也把它称为控制反转(IoC)

关于这个主题的开创性文本是Martin Fowler的文章,但从那时起我们已经走了很长的路,所以一定要检查一些最近的文本

您可以手动实现DI,比如,或者让DI容器(即框架)为您完成工作

常见的DI容器有:


我认为不能将两者完全分开,但可以确保依赖关系不是双向的

我认为定义以下几点很重要:

  • 模型对象(例如,人员、地址、订单等)
  • 持久层(例如DAO、存储库等)
  • 服务层(接口,其方法映射到用例、了解工作单元等)
  • web或视图层(用于web应用的控制器/页面,用于桌面的小部件)
  • 持久性层、服务层和视图层了解模型对象;模型对象对其所在的层不敏感

    层的依赖关系是单向的,并从前向后流动:

    • 持久性->模型
    • 服务->模型,持久性
    • 查看->模型、服务
    您可以从后面到前面进行单元测试,因为依赖关系使模拟变得容易

    不可能没有依赖项,但是您应该设计它们,这样就没有循环


    唯一一个没有依赖项的类是没有人调用并且从不调用其他类的类。这既不是有用的设计目标,也不是有价值的设计目标。

    n层设计:在业务逻辑层,您可以创建数据访问类和数据操作类。始终编程到一个接口。

    这就是我们所做的,但我们也将其与DTO结合起来。我看不到Nosredna问题上的“良好的关注点分离”。我认为这篇文章可能会澄清一些概念,并提供帮助。好帖子,达菲莫!
    //business class fragment
    public bool Save()
    {
        if(this.IsValid)
        {
           //DataProvider is one of many data access classes that implement an IDataProvider interface.  Switched elsewhere in the class.  This allows switching of Database providers, xml, etc.
           DataProvider.Save(this);
           return true;
        }
        return false;
    }
    
    public List<MyBusinessObject> GetObjectsByCriteria(string criteria)
    {
        return DataProvider.GetMyBusinessObjectsByCriteria(criteria);
    }