你们当中有多少人从事3层设计?
对于数据库驱动的应用程序,多年来,三层设计一直是我的标准设计理念,但从未使我失败。对于那些练习它的人,请描述图层。
我发现许多人混淆了业务层和数据访问层,使其更像2.5层设计。
我更喜欢使用存储过程将数据层几乎全部移动到数据库中,并且在代码中只有一个非常轻量级的数据层,它将存储过程调用包装到业务对象中。
我们如何处理?
编辑:如果我们要做的只是定义3层,请不要浪费时间回复。我正在寻找特定的人如何实现它,我们使用存储过程还是ORM,如何处理DAL和BLL之间的循环依赖关系?除了说之外,这个话题还有很多深度
- 使用者介面
- 商业
- 数据
解决方案
我们曾经使用以下方法进行处理:
用户界面层(所有用户界面所在的位置)
业务层(所有业务逻辑都在其中)
数据层(所有数据库访问都在其中)
3层:
- 数据库后端-充当数据存储,我们还强制执行数据库中的依赖关系
- C#业务层-处理通过http(通过aspx页面接收)提交的用户请求,根据数据库状态收集正确的响应,然后通过xml将其返回给客户端(尽管我建议使用json)
- javascript前端-以用户友好的方式处理xml渲染
我练习3层设计的方式与我们使用存储过程来处理大多数(即使不是全部)与数据库通信的方式几乎相同。我设计类的方法是为了使每个类都有特定的目的,以降低复杂性并在进行更改时具有更大的灵活性。
我在三层设计中遇到的最大问题之一是在哪里进行输入验证。我经常发现自己在UI和业务层中都重复验证,以便通过快速验证检查使用户受益,并确保进出数据层的数据有效。我们如何处理验证?
我已经从事主要的Web应用程序已有一段时间了,并且也关注3层:
UI:纯ASPX页面。实际上,有时很难从此处向下推业务层,因为在此处进行快速计算或者执行某些操作似乎很容易。但是,我已经受到足够的训练,以确保页面后面的代码除了显示/隐藏面板,更新用户输入等之外什么都不做。
DAL:所有数据访问层的东西。我非常喜欢使用可用的XSD / DataTable / TableAdapter类。我还使用基于存储过程的CRUD方法,因此将适配器连接到存储的过程很容易。
BLL:在我的大多数应用程序中,业务层往往是三层中最薄的,因为它们主要是CRUD类型的应用程序,并内置了一些报告。
n层设计
我认为分层效果很好。看一下OSI模型中的层。我使用了我们描述的三个层次,这种方法确实有所帮助。在大型桌面应用程序中,Model View Controller的抽象通常很有帮助。我们可以将事物分成越来越小的,更易于管理的部分。有一点是收益递减。而且,有时候我们想删除抽象层,也许直接与硬件对话,这取决于我们应用程序的目标。
DI为我取代了等级。是的,我们仍然可以按层对提供程序进行逻辑排序,但是逻辑层和数据库层之间的差异已被其他设计问题(恕我直言)模糊了。如果我们不确定我的意思,请查看"贫血模型"战争。
更多附带说明:永远不要忘记,n层分层是逻辑分层,而不是进程的物理分离。即,不需要与表示代码在不同的流程(或者在不同的框内)运行业务逻辑。重要的是保持代码干净。
物理上分离表示代码和业务逻辑已经被宣传了一段时间,例如通过使用Web服务连接到后端。在某些情况下,这是个好主意,但并不一定要这样做,但会使体系结构,部署,设计和成本性能大大复杂化。
我们使用大约6层设计。
- 浏览器端Javascript和其他功能。这是纯的视觉糖,几乎没有商业价值或者加工价值。这里的任何输入验证都是多余的检查-它们可以被绕过,因此我们不信任它们。
- 服务器端HTML演示文稿。这部分是由业务规则驱动的。但是我们使用的模板语言没有任何处理。
- 服务器端视图功能,业务逻辑"控制"。在这里进行导航,验证和"高层"面向应用程序的处理。发生状态更改的地方-计算,更新,删除等。这是处理过程。这是强制执行身份验证和授权的地方。
- 模型定义(使用ORM层)。这是对象模型。它映射到关系模型。它包括所有模型级处理作为对象方法。在这里完成一些计算,在此定义过滤,计数,排序。这是我们有用的数据视图。
- 访问层(某种数据库连接性)。取决于数据库产品。它是由ORM层管理的,因此我们无需进行任何编码,只需进行配置即可。
- 持久存储在数据库中(没有存储过程,没有触发器)。
我发现2.5层设计最适合于我创建的新Web应用程序。
我通常从2个类库和1个Web应用程序开始。
Company.Data
(类库)Company.Web
(类库)(包含PageBase
,自定义控件,Helper函数等)- Company.Web.WebApplication(Web应用程序)
对于我创建的应用程序,我仅使用存储过程来访问数据。
实际上,我已经创建了CodeSmith模板来生成所有存储过程,数据和业务类。
Company.Data
该程序集主要由实体数据类和集合组成。
例如,我通常在Web应用程序中有一个名为"设置"的表。
将生成一个名为" Setting"和" SettingCollection"的类。
因此,如果我需要加载特定设置,则可以执行此操作。
Dim setting As New Setting(1) 'pass in the id of the specific setting setting.Value = "False" 'change the value setting.Save() ' Call the save method to persist changes back to the database
或者创建一个新设置,我只是没有在构造函数中传递值
Dim setting as New Setting() setting.Name = "SmtpServer" setting.Value = "localhost" setting.Save()
我在Company.Data程序集中的名称空间通常看起来像这样。
Company.Data.Entites Company.Data.Collections Company.Data.BusinessObjects
(此名称空间用于创建自定义方法以访问数据)
我还基于主键,外键和唯一索引生成自定义方法。
例如,设置表中的名称列具有唯一索引。
一个名为" GetSettingByName"的共享方法将自动生成,这将返回一个设置对象。
该方法将在Company.Data.BusinessObjects名称空间中
对于实体和业务对象类,将生成两个文件。每次生成1个,可编辑且仅生成1个
第一次。我使用部分类允许我添加自定义代码,而不会被覆盖。
对我来说,这种方法非常有效。 Codesmith的生成为我节省了无数的编码时间。我可以在表格中添加5个新列,然后重新生成
所有新代码都以秒为单位。存储的过程将被删除并重新创建。
2.5层设计效果很好,因为我的应用程序将只使用一个数据库,即Sql Server。将来不会发生使用access,oracle,mysql的需要。