设计模式:需要帮助理解这个概念以及它如何应用于我的项目

Posted

技术标签:

【中文标题】设计模式:需要帮助理解这个概念以及它如何应用于我的项目【英文标题】:Design Patterns: Need help understand to this concept and how it applies to my project 【发布时间】:2011-05-22 11:35:08 【问题描述】:

在过去的几天里,我使用 DAL/BLL/UI 方法进行了大量研究,但并没有非常清楚地了解它将如何应用于我的项目。过去,我省略了将我的 UI 直接连接到数据访问层 (LINQtoSQL dbml) 的 BLL。但是,我认为这不是我现在(甚至可能是过去)工作的地方的好主意,因为我们有很多不同的应用程序,我想使用与构建它们相同的 DAL/BLL。

我的问题是,在我的大多数应用程序中,当我真正做的只是使用 LinqtoSqlDataSource/GridView 连接到我的数据上下文以处理所有更新/编辑等时,BLL 如何帮助我。另外,在某种程度上,每个新的 Web 应用程序都需要对 DAL/BLL 进行唯一更改才能获取所需数据,这可能会影响使用相同 DAL/BLL 的其他应用程序。重用 DAL/BLL 是正确的做法还是我遗漏了什么?

我认为 BLL 在我需要构建(例如,将要构建的各种 Web 应用程序的安全类)时发挥作用。但是,当我使用 Linqtosql 数据源时,为什么还要费心将它连接到 BLL?

DAL

LinqToSQL dbml 数据上下文。 使用 LinqToSQL 是否会改变我应该如何使用此设计?

BLL

公司使用的各种网站的安全性。 查询 DAL 在使用 LinqToSQLDatSource 时返回什么(?),处理各种结果集的函数(我真的不确定这应该如何与 BLL 一起使用,如果问题不清楚,请见谅)

用户界面

仅引用 BLL?

【问题讨论】:

【参考方案1】:

DAL 和 BLL 由一个通常微妙但关键的区别分开;商业逻辑。听起来很简单,但让我进一步解释一下,因为这些区别可能非常精细,但对架构的影响却很大。

使用 Linq2SQL,该框架生成非常简单的对象,每个对象代表一张表中的一条记录。这些对象是 DTO;它们是只有字段的轻量级 POCO(Plain Ol' CLR Object)类。 Linq2SQL 框架知道如何从 DB 数据中实例化和水合这些对象,并且类似地,它可以将包含在其中的数据消化到 SQLDML 中,从而创建或更新 DB 记录。然而,在这个级别上,控制各种对象的字段之间关系的规则很少或根本不知道。

您的实际领域模型应该比这更智能;至少足够聪明地知道一个名为 SubTotal 的 Order 对象上的属性应该等于所有 OrderLine 的所有 ExtendedCost 的总和,同样地,ExtendedCost 应该是 UnitPrice 和 Quantity 的乘积。在许多现代程序中,您的域构成了 BLL 的一部分,至少在这个程度上是这样。 Linq2SQL 创建的对象可能不必知道所有这些,特别是如果您没有持久化 SubTotal 或 ExtendedCost。如果您依赖 Linq2SQL DTO,那么您基本上已经将自己绑定到所谓的贫血域模型,这是一种已知的反模式。如果域对象至少不能保持自身内部一致,那么任何与域对象一起工作的对象都必须被信任以保持这种状态,这要求所有这些对象都知道它们不应该知道的规则。

UI 应该了解域,或者如果您愿意,它应该知道一些抽象的方式来从域中获取数据以用于读写目的(通常封装在称为控制器的对象中,它与域层和/或LINQ2SQL)。 UI 不必知道任何中等大小或更大的程序中的数据库;域对象可以通过对 DAL 中的对象的引用来对自身进行水合,或者它们由 DAL 中的自定义对象生成,您创建这些对象以进行水合,然后将其提供给控制器。连接的 ADO 模型和与 GridViews 的互操作令人钦佩,但它不允许抽象。假设您想在域和 UI 之间插入一个 Web 服务层,以允许 UI 位于处理仓库中数据的移动应用程序上。您必须重建您的 UI,因为您不能再直接从 Linq2SQL 获取对象;您可以从 Web 服务中获取它们。如果您有一个与 Linq2SQL 对话的控制器层,您可以用与 Web 服务对话的控制器替换该层。这听起来像是一个微小的区别。你总是需要改变一些东西。但是,现在您在移动应用程序和桌面应用程序上使用完全相同的 UI,因此不必因为这两个层以不同的方式获取数据而在该层进行两次更改。

【讨论】:

您的回答和***.com/questions/3952534/… 让我对领域方面有了一些了解,但我仍然不明白它是什么。你能详细说明一下吗? “域”基本上是“有状态业务对象”的集合;例如,在 Quickbooks 这样的程序中,Invoice 可能是域对象。这些对象通常非常紧密地映射到 RDBMS 的数据结构,并负责维护一致的数据状态(因此它们是数据级验证和更新总计等“计算字段”的常用位置。 领域层到底应该有多少逻辑是程序员之间不断分歧的根源。基本上,一个对象对自己和周围的对象了解得越多,对象必须改变的原因就越多;这违反了 SOLID 的单一责任原则,该原则规定对象应该有一个确切的理由来改变。但是,如果域类具有存储状态的单一职责,则会创建一种称为贫血域模型的反模式,该模型需要更改多个对象(域类、验证器、持久性)来进行甚至很小的业务更改。【参考方案2】:

这是一个很好的问题,我已经用我们的目录应用思考了一年。对我来说,一个具体的例子可能会对你的模式有所帮助。

我有一个页面来显示购物车的内容。在“早期”,这个页面有一个由 SQL 存储过程的结果填充的网格,给定订单号,列出购物车中的物品。

现在我有一个“购物车”BLL 对象,其中包含“行”对象的集合。网格是一样的,但数据源是购物车的行。

我为什么要这样做?最初,不是因为任何花哨的设计模式。根据每一行中的字段,我有很多特殊情况要处理,而且我还有其他地方需要显示相同的购物车内容数据,构建对象更有意义。现在从存储库加载购物车,我的页面不知道该存储库的作用。哎呀,为了测试,它是硬编码的购物车数据。

然后购物车使用存储库来加载行。每一行都有自己操作的逻辑,不知道数据来自哪里。

希望这有帮助吗?

【讨论】:

当您说“购物车的行”时,您是指来自 BLL 的购物车对象?

以上是关于设计模式:需要帮助理解这个概念以及它如何应用于我的项目的主要内容,如果未能解决你的问题,请参考以下文章

内存使用、cpu 时间、数据输出和文件系统存储如何应用于我的网站?

导航抽屉,概念问题

iBeacon是如何唤醒我们的应用程序的?多长时间?以及如何延长时间?

如何将 testthat 测试应用于我的包中与特定命名模式匹配的所有函数?

实例初涉业务的时候,概念建模是如何快速帮助我们理解业务的?

什么是 firebase 以及如何在 Android 中使用它? [关闭]