2010-08-25 57 views
2

我是NTiers对我的发展选择的忠实粉丝,当然它并不适合所有情况。业务层结构,你如何建立你的?

我目前正在研究一个新项目,我正在努力尝试一下我通常的工作方式,并试图查看我是否可以清理它。由于我一直是一个非常糟糕的男孩,并且在表示层中放置了太多的代码。

我的正常业务层结构是这样的(它的基本观点):

  • 业务
    • 服务
      • FooComponent
        • FooHelpers
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • BahWorkflows
    • 公用事业
      • 常见
      • 的ExceptionHandlers
      • 进口商
      • 等...

现在上述我有很大的访问直接保存Foo对象和呸对象,通过各自的助手。

XXXHelpers让我可以访问保存,编辑和加载相应的对象,但我在哪里放置逻辑来保存具有子对象的对象。

例如:

我们有以下对象(不,我知道很好的对象)

  • 员工
  • EmployeeDetails
  • EmployeeMembership
  • EmployeeProfile

目前我w应该在表示层中构建这些代码,然后将它们传递给他们的帮助者,我认为这是错误的,我认为数据应该传递到业务层以上的某个地方并在那里进行排序。

但是我对于在哪里放置这个逻辑以及该怎么称呼这个扇区感到有点不知所措,它会作为EmployeeManager或者类似的东西下到Utilities中吗?

你会做什么?我知道这是所有的偏好。

更详细的布局

的工作流程直接包含所有的呼叫到DataRepository例如:

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

然后佣工提供商进入工作流程:

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

这是减少重复的代码,因为您可以在工作流程中调用一次getBySomeProperty ,然后在Helper可以进行其他操作并以不同的方式返回数据,一个不好的例子是public GetByIdAsc和GetByIdDesc

通过使用DataRepository分离对数据模型的调用,这意味着可以换出另一个实例的模型(这就是思想),但ProviderHelper没有被分解,所以它不可互换,因为它不幸是EF的硬编码。 我不打算改变接入技术,但在未来可能会有更好的东西,或者只是所有酷酷的孩子现在正在使用的东西,我可能想要实现。

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

(取决于应用程序的调用是什么)

projectName.web 
projectName.mvc 
projectName.admin 

测试项目

projectName.Business.Tests 
projectName.Data.Test 

回答

3

+1为一个interesti问题。

所以,你描述的问题是相当普遍的 - 我会采取不同的方法 - 首先是逻辑层,其次是实用程序和帮助程序的命名空间,我会尝试和完全分解 - 我会告诉你为什么在一秒钟。但是首先,我的首选方法是相当常见的企业架构,我会尽量简要地强调一下,但这里有更多的深度。它的确需要一些根本性的改变 - 使用NHibernate或者Entity框架来让你直接查询你的对象模型,让ORM处理诸如映射到数据库和从数据库映射到延迟加载关系等等。这样做可以让你实现您在域模型中的所有业务逻辑。

首先层级(或解决方案中的项目);

YourApplication.Domain

域模型 - 代表你的问题空间中的对象。这些是包含所有关键业务逻辑的普通旧CLR对象。这是您的示例对象所在的位置,它们的关系将被表示为集合。这个层没有处理持久性等的东西,它只是对象。

YourApplication。数据

库类 - 这些都是与得到您的域模型的聚合根(一个或多个)处理类。

例如,您不希望看到EmployeeDetails而不看员工(假设我知道,但您得到的要点 - 发票行是一个更好的例子,您通常会得到通过发票发票行,而不是独立加载它们)。因此,对于每个聚合根具有一个类的存储库类,将负责使用所讨论的ORM从数据库中获取初始实体,实现任何查询策略(如分页或排序)并将聚合根返回给消费者。存储库会消耗当前活动的数据上下文(NHibernate中的ISession) - 这个会话是如何创建的取决于你正在构建的应用程序类型。

YourApplication.Workflow

  • 也可以被称为YourApplication.Services,不过这可以通过Web服务
  • 这一层是所有关于相互关联的,复杂的原子操作相混淆 - 而不是有一堆要在您的表示层中调用的东西,并因此增加耦合性,可以将这些操作包装到工作流或服务中。
  • 这是可能的,你可以在许多应用没有这个事。

其他层则取决于你的架构和你正在实施中的应用。

YourApplication.YourChosenPresentationTier

如果您使用网络服务来发布你的层次,那么你会创建表示只是你的域和消费者之间暴露数据DTO合同。您将定义可知道如何将数据移入和移出域中的这些合同的汇编程序(您绝不会通过线路发送域对象!)

在这种情况下,您也正在创建客户端,会消耗上面定义的表示层中的操作和数据契约,可能会直接绑定到DTO,因为每个DTO都应该是特定的视图。

如果你不需要分发你的层,记住分布式体系结构的第一条规则是不分发,那么你将直接从asp.net,mvc,wpf,winforms等等中使用工作流/服务和存储库。 。

这只是留下了数据上下文建立。在Web应用程序中,每个请求通常都非常独立,因此请求范围上下文是最好的。这意味着上下文和连接在请求开始时建立,并在最后处理。让您选择的IoC /依赖注入框架为您配置每个请求组件是很简单的。

在一个桌面应用程序,WPF或WinForms的,你必须每形式的上下文。这确保了编辑对话框中的域实体的编辑可以更新模型,但不会将其添加到数据库(例如:选择“取消”)不会干扰其他上下文,或者更糟糕的是最终被意外持续。

依赖注入

上述将首先定义为接口,与具体实现通过IOC和依赖注入框架实现的所有(我的偏好是城堡温莎)。这使您可以独立地对单个层进行隔离,模拟和单元测试,并且在大型应用程序中,依赖注入是一种生命保护程序!

这些命名空间

最后,我之所以会失去佣工命名空间是,在上述模型,你不需要他们,也一样实用的命名空间,他们给懒惰开发商借口不思考一段代码在逻辑上的位置。 MyApp.Helpers。*和MyApp.Utility。*只是意味着,如果我有一些代码,说MyApp.Data.Repositories.Customers内,也许在逻辑上属于一个异常处理(也许这是一个客户的裁判不是唯一的例外),水上开发人员可以将它放在MyApp.Utility.CustomerRefNotUniqueException中,而不必考虑。

如果您有需要包,添加一个MyApp.Framework项目和相关的命名空间的共同框架类型代码。如果your're添加新的模型绑定,把它放在MyApp.Framework.Mvc,如果是普通的日志记录功能,把它放在MyApp.Framework.Logging等。在大多数情况下,应该不需要引入实用程序或助手名称空间。

结束语

这样皮毛 - 希望这是有一定的帮助。这就是我今天开发软件的方式,而且我故意试图简短一些 - 如果我能详细说明任何细节,请告诉我。最后要说的是,对于这个褒贬不一的观点来说,以上是对于合理的大规模开发 - 如果你正在写记事本第2版或公司电话簿,上面的内容可能总是过度杀伤!

干杯 托尼

+0

那一个伟大的,我会张贴我用的是结构完整的轮廓,我只是上面显示的业务层,我也并不只是把它的业务;)很多东西你上面说的是伟大的,但对于公用事业的原因它放置XML泛型等通用类,因为它们不直接链接任何东西。无论如何,我会发布更好的结构支出,因为你已经覆盖了所有其他层次,而不仅仅是业务。 – JamesStuddart 2010-08-26 08:20:17

+0

您的XML串行器可能属于您的数据层。例如,我有一些XML序列化的东西,负责从第三方供应商处获取数据。它生活在MyApp.Data.Repositories.Integration - 我还没有发现需要什么名字像通用“工具” – 2010-08-26 09:35:27

+0

把你的设置管理,例如 - 对我来说,只是住在projectName.SettingsManager - 在.Utilities.Common ISN不那么直观。这当然是一个偏好问题! :) – 2010-08-26 09:37:50

0

有一个很好的图,此页关于应用布局上的说明,alhtough长相进一步下跌的文章心不是分成物理层的应用程序(独立的项目) - Entity Framework POCO Repository

+0

实体框架POCO Repository的链接已经死了,无论如何你有一个更新的链接? – 2016-03-20 01:13:01

+0

5年前的这篇文章,但我设法通过WaybackMachine找到它 https://web.archive.org/web/20120605/http://blog.keithpatton.com/2009/05/30/Entity +框架+ POCO +仓库+使用+视觉和Studio + 2010 +网+ 40 + Beta版+ 1.aspx – JamesStuddart 2016-03-22 08:05:21