热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ActiveRecordvsDataMapper模式–实用性比较

ActiveRecord和DataMapper是两种最流行的模式,用于把应用对象映射到数据库。选择哪种方式取决于项目的大小和复杂性,相对于预期开发时间的代码质量和花费,以及许多其他






Active Record和Data Mapper是两种最流行的模式,用于把应用对象映射到数据库。选择哪种方式取决于项目的大小和复杂性,相对于预期开发时间的代码质量和花费,以及许多其他方面。今天我会对二者都进行阐述。

意外断电,内存溢出,进程中断,由于避免重复的SQL代码而节约的时间和成本。有许多原因会促使你去将对象存储到关系数据库中。我想你猜到接下来要描述的了……

对的-你需要一种对象关系映射用于从数据库获取所需的数据,最可能的情况是,你将选用其中一种,Active Record或者Data MApper。

我们的应用功能基本都是CRUD-或基于领域模型的。大多数是兼而有之。为什么我们只能选用一种而不是都采用两种呢?在这篇文章中我将尝试去回答这个问题以及其他相关问题

让我们先快速回忆下ORM是什么。


ORM – when to use it?

在编程中使用面向对象范式带来一种解决方案,可以让你将对象抽象映射到数据库中数据。这被称为ORM。
ORM背后的通用思想

ORM是一种特别的数据映射层,提供了从应用到数据库的数据访问,这意味着它简化了应用到数据库的访问。这个解决方案的忠实支持者和批评者是一样多的。选择使用或不使用取决于应用的驱动。主要的驱动因素包括:



  • performance, 性能
  • scalability, 可扩展性
  • maintainability, 可维护性
  • productivity.生产率

把ORM使用好需要掌握许多的知识,但如果你选择不使用它,你需要给相同的问题提供另外一种解决方案。在你下定决心之前,你需要考虑替代方案将要花费的时间和精力。

在我看来,ORM是一种神奇的工具。它大大提高了你的生产效率,你不需要写复杂的映射过程,并且代码将会变得更易维护。最好的使用方式是当你需要模型的读写分离时。


ORM在写的模型中工作的很好,但是在读的模型中只有一些案例中才比较好。


查询构造器是ORM的核心组件之一,对构造经过优化和易读的查询是非常有帮助的。这也是为什么它在读模型中有用处。同时,你必须注意到这时的读模型不能用到域对象。这是属于写模型的部分功能。按这个思路,你会使用更多的getter并使用不必要的对象关联影响性能,这是非常低效的。

在读模型中使用ORM实体使得可以修改查询结果的状态,这是违背读写分离的原则(CQS)。原则规定,问问题不能引起结果发生变化。

正如之前我说的,有两种主要的方案来实现对象关系映射。


Active Record模式

在Active Record 模式中,模型对应数据库中一张表或一张视图。这种机制是非常简单易懂的。每个类实体对应表格中一条数据。

简单方案通常都有许多限制。AR模式适用于简单模型,即那些没包含复杂业务逻辑的。他是简单CRUD应用的理想工具。伴随越来越多复杂模型的引入,事情会变得越来越难处理。在这种情况下,很难去扩展这样的一个应用。


Data Mapper模式

在Data Mapper模式中,模型就是一个模型类。这个类用于展示业务逻辑,同时包含了行为和数据。这一层代码把内存对象和数据库隔离。我们不知道它是怎么样,以及在哪里存在的。

因此,你有了一个独立的层,用于在代码和数据库之间传数据。并且还必须注意隔离他们。为此,Data Mapper提供了灵活性以及更加重要的独立性

学习更多:微服务中的设计模式




  • 面向CTO的微服务中的设计模式。API网关、前台的后端等


使用Active Record模式的后果

使用任意一个这些模式都会有类似效果。


步入过程式编程领域

Active Record遵循数据库优先原则。你创建一个数据库,然后再在代码中模型化它。使用Active Record会引导你进入贫领域模型(Anemic Domain Model)? 清醒点吧,这并不是进步。这意味着你的实体将不包含逻辑。你将会把所以的逻辑放到services层(不要是控制器层,我希望)。总之,model将会是一个被其他类控制的数据袋子。这有什么坏处呢?这可能导致进入过程式编程,而不是面向对象模式。


无封装

需要额外说明的是,模型并不能确保它的状态正确性,因为可能由于错误的使用getters和setteres方法修改了它。这种改变没有封装性,而这是OOP编程的基础思想。我这里不是要说getters和setters方法是错误的,而是要表明,它们应该展示由业务规则产生的行为。


No SRP

你的代码将强依赖数据库。这也违背了单一责任原则(SRP)。怎么会呢?因为模型中包含了数据库交互逻辑。这不是最好的设计,但他确实加速了开发


可测试性问题

最后一个进入我脑子的问题是低可测试性(poor testability)。这种模型是最难测试的,并且不是在所有案例中要求的。

你是否像DTOs那样测试简单对象?那正是我所想的。这里你可以不需要去做这个。然而,这并不意味着你可以跳过所有测试。在服务中逻辑是无处不在的。因此,你需要更多的集成测试(测试中的钻石)




使用Data Mapper模式的后果


分层隔离

Data Mapper遵循代码优先原则。你可以推迟保存数据直到最后,这样可以专注在代码上。model不知道其他层的任何事,它是非常单一的。一个好的模型设计应该是无数据库关联的。持久层是另一个层,领域不应该依赖他。


我的观点是,分离出这个层是Data Mapper最大的优点。另一方面,没有层分离是Active Recode最弱的地方。


我并不是说所有的应用都使用只包含行为的富领域模型。而是,我相信Data Mapper也会是简单模型的好设计。你可以像Active Record那样设计使用它,同时你又获得了层分离的能力。当然,这不是没有任何代价的-这样的方式更复杂并且有更高进入屏障。


提高可测试性

使用Data Mapper不能确保会得到一个设计良好的模型。事实上,我看到了不少使用Data Mapper设计的坏模型(其中一些是我写的)最重要的一点,它不会干扰创建封装良好的模型。由于这一点,你可以通过单元测试获得更好的可测试性(测试中的金字塔)


PHP最流行的几种实现

处于PHP生态中的人应该知道Eloqueent和Doctrine。如果你不熟悉它们,当前你应该知道的是它们都属于ORMs。Eloquent是基于Active Record模式,Doctrine是基于Data Mapper模式的。

我相信这是领域模型该有的样子-存粹,没有任何的依赖性。一个模型不应该关心它该如何持久化。由于这一点,它必须能正常工作,不要去考虑它是存储于RDBS,NoSQL还是任何其它地方。哪种模式能够支持这一点呢?Active Record无法应对这个问题,Data Mapper也许是那个解决方案.


Eloquent中领域模型的实现

如果你使用的是Eloquent,你马上会对Illuminate\Database\Eloquent\Model增加一个依赖。当然了,还有一个隐藏的数据库连接。你没有定义清晰的字段。至少不是非常明确的,因为你可以使用PHPDoc这样的解决方案去优化它。在Laravel框架中呈现的又是什么样子呢?它将会使用一个简单的Employee模型和一个service类(例如:Employer),类中有一个dismiss()方法,用于设置适当的一个值。


Doctrine中领域模型的实现

如果你使用的是Doctrine,你完全可以使用这种模式(领域模型)。我喜欢这个实现。为实现这个方式,你需要在扩展文件中使用XML映射。这个在Symfony中如何展现? 在Employee实例中调用dismiss()方法,保存时使用EntityManager或者EmployeeRepository。模型是干净存粹的。然而Doctrine中有一个扩展依赖是不可避免的:Doctrine\Common\Collections\ArrayCollection.

我希望这个在将来可以得到修正。就现在而言,我接受这种独立的包形式并且被很好的封装,将来可以被很容易的替换掉。客户端代码不应该使用它,也不知道领域模型正在使用它。


存储库模式

让Active Record更优雅的一个建议是使用仓储模式,这是遵循依赖反转原则的一种实现。它将帮助你实现分层结构。在将来,你可以很容易的用另外一种工具替换Eloquent。
另外,这将成为一个常规操作。有时候你希望保存你的数据在另外一个存储库中,比如NoSQL。不管怎样,仓储模式允许你在没有数据库连接的情况下编写内存中的假实现。

我知道,这看起来像一个毫无用处的层次,但实际上它不是。仓储层帮助你避免了重复的查询。非常酷的是,当你需要改变一些字段时,你可以在一个地方很容易的找到它们。


独立于ORM的模型

我曾经见过的一种可能性实现是分别为领域和数据库创建模型-不管实现方式是用Doctrine(Data Mapper)还是Eloquent(Active Record)。

但是,在我观点里,这又是增加了一个层,一个无用的层。这个方案还有另外一个我不喜欢的点是,它需要从一个对象转移到另外一个对象。所有领域模型中的字段必须要有getters。你也应该只在第一次初始化时使用构造函数创建一个对象-这是方案中很难做到的一个点。这对Eloquent来说是好的解决方案,但是Doctrine不需要这种独立的两个模型来实现逻辑分层。


Active Record vs Data Mapper – 哪种是正确的选择?

以下是对比,总结如下:



  • Data Mapper模式可以让你不出问题的情况下创建简单CRUD应用,同时可以在更复杂的应用中使用。
  • 乍一看,Data Mapper似乎是一个更好的解决方案。或者说得更准确些–更有质量。另一方面,质量并不总是最重要的东西。我知道–这听起来是反直觉的。 质量与交付时间和成本都有关系。你总是可以做得更好,但你需要在时间和成本方面定义一个可接受的质量水平,并为之努力
  • 在为Active Record辩护上,我见过许多项目,它们应该是简单的应用程序,具有直接的实际业务领域,但它们的实现方式使它们难以理解。Data Mapper模式使得在网络应用中更容易坚持良好的编程实践、干净的代码和架构,但它也更加复杂。如果你不能正确使用它,Active Record的实现可能会变成简单项目的更好选择。
  • 解决复杂的问题很重要,也很有意义,但你也应该努力限制新问题的产生。这就是为什么我喜欢模块化,因为你可以在不同的模块中使用各种解决方案,而不会造成不必要的混乱。此外,为一个给定的问题寻找解决方案会变得更简单。

程序员喜欢假装他们只处理复杂的问题。事实是,他们工作的很大一部分是解决典型的挑战,如创建简单的CRUD应用程序。这就是为什么我不喜欢说某个东西本身就是一个糟糕的解决方案(反模式)。

没有什么总是好的或者坏的-需要一个适当的背景。一个程序员的工作是简化解决方案,让代码能够被其他的程序员更好的阅读和管理。

老实说,我几乎总是使用Data Mapper,它适用于简单和复杂的应用。然而,如果我使用Active Record,那将是用于逻辑相对简单的应用程序。

翻译自:tsh.io/blog/active-record-vs-data-...




推荐阅读
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • Framework7:构建跨平台移动应用的高效框架
    Framework7 是一个开源免费的框架,适用于开发混合移动应用(原生与HTML混合)或iOS&Android风格的Web应用。此外,它还可以作为原型开发工具,帮助开发者快速创建应用原型。 ... [详细]
  • 本文详细介绍了如何解决DNS服务器配置转发无法解析的问题,包括编辑主配置文件和重启域名服务的具体步骤。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 从0到1搭建大数据平台
    从0到1搭建大数据平台 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 本文讨论了在进行 MySQL 数据迁移过程中遇到的所有 .frm 文件报错的问题,并提供了详细的解决方案和建议。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 在PHP中如何正确调用JavaScript变量及定义PHP变量的方法详解 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • 本文对SQL Server系统进行了基本概述,并深入解析了其核心功能。SQL Server不仅提供了强大的数据存储和管理能力,还支持复杂的查询操作和事务处理。通过MyEclipse、SQL Server和Tomcat的集成开发环境,可以高效地构建银行转账系统。在实现过程中,需要确保表单参数与后台代码中的属性值一致,同时在Servlet中处理用户登录验证,以确保系统的安全性和可靠性。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 系统转换的三种方法及其具体应用分析
    系统转换是信息技术领域中常见的任务,本文详细探讨了三种主要的系统转换方法及其具体应用场景。这些方法包括:代码迁移、数据迁移和平台迁移。文章通过实例分析了每种方法的优势和局限性,并提供了实际操作中的注意事项和技术要点。例如,代码迁移适用于从VB6获取网页源码,数据迁移在Ubuntu中用于隐藏侧边栏,而平台迁移则涉及Tomcat 6.0的使用和谷歌爬虫的测试。此外,文章还讨论了蓝翰互动PHP面试和5118 SEO工具在系统转换中的应用,为读者提供了全面的技术参考。 ... [详细]
author-avatar
mobiledu2502929493
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有