普通的旧CLR对象与数据传输对象

时间:2009-04-07 12:08:22

标签: c# .net poco dto

POCO =普通旧CLR(或更好:类)对象

DTO =数据传输对象

在这个post中存在差异,但坦率地说,我读到的大多数博客都以DTO的定义方式描述了POCO:DTO是用于在应用程序层之间移动数据的简单数据容器。

POCO和DTO是一回事吗?

9 个答案:

答案 0 :(得分:550)

POCO遵循OOP规则。它应该(但不必)具有状态行为。 POCO来自POJO,由Martin Fowler [anecdote here]创造。他使用术语POJO作为一种方法,使其更容易拒绝框架繁重的EJB实现。 POCO应该在.Net中使用相同的上下文。不要让框架决定你的对象的设计。

DTO的唯一目的是转移状态,而且应该没有行为。有关使用此模式的示例,请参阅Martin Fowler的explanation of a DTO

这就是区别: POCO描述了一种编程方法(良好的老式面向对象编程),其中 DTO是一种模式,用于“传输数据”对象。

虽然您可以像对待DTO一样处理POCO,但如果您这样做,则可能会产生anemic domain model。此外,结构不匹配,因为DTO应设计为传输数据,而不是代表业务域的真实结构。结果是DTO往往比实际域更平坦。

在任何合理复杂的领域,您几乎总是更好地创建单独的域POCO并将它们转换为DTO。 DDD(域驱动设计)定义了anti-corruption layer(另一个链接here,但最好的办法是buy the book),这是一个很好的结构,可以清除隔离。

答案 1 :(得分:49)

由于我已在博客文章中说明了自己的立场,因此对我来说可能是多余的,但该文章的最后一段总结了一些内容:

所以,最后,学会爱POCO,并确保你不会传播任何与DTO相同的错误信息。 DTO是用于在应用程序层之间移动数据的简单数据容器。 POCO是完全成熟的业务对象,其中一个要求是Persistence Ignorant(无get或save方法)。最后,如果你还没有查看Jimmy Nilsson的书,请从你当地的大学校园里拿出来。它有C#中的示例,这是一个很好的阅读。

顺便说一句,帕特里克我读过POCO作为一篇生活方式的文章,我完全同意,这是一篇很棒的文章。这实际上是我推荐的吉米尼尔森书中的一部分。我不知道它是否可以在线获取。他的书确实是我在POCO / DTO / Repository /和其他DDD开发实践中发现的最佳信息来源。

答案 2 :(得分:27)

POCO只是一个不依赖于外部框架的对象。这是普拉。

POCO是否有行为是无关紧要的。

DTO可能是POCO,也可能是域对象(通常会有丰富的行为)。

通常,DTO更可能依赖外部框架(例如属性)进行序列化,因为它们通常会在系统边界处退出。

在典型的洋葱风格体系结构中(通常在广泛的DDD方法中使用),域层位于中心,因此其对象在此时不应具有该层之外的依赖关系。

答案 3 :(得分:14)

我为该主题撰写了一篇文章:DTO vs Value Object vs POCO

简而言之:

  • DTO!=价值对象
  • DTO⊂POCO
  • 价值对象⊂POCO

答案 4 :(得分:6)

我认为DTO可以是POCO。 DTO更多地是关于对象的使用,而POCO更像是对象的风格(与架构概念分离)。

POCO与DTO不同的一个例子是当你在域模型/业务逻辑模型中讨论POCO时,这是你问题域的一个很好的OO表示。您可以在整个应用程序中使用POCO,但这可能会产生一些不良副作用,例如知识泄漏。例如,DTO是从与UI通信的服务层使用的,DTO是数据的平面表示,并且仅用于向UI提供数据,并且将更改传送回服务层。服务层负责将DTO的两种方式映射到POCO域对象。

更新 Martin Fowler said这种方法很难走,只有在域层和用户界面之间存在严重不匹配时才应采取这种做法。

答案 5 :(得分:2)

这是一般规则:DTO ==邪恶和过度设计软件的指标。 POCO ==好。 “企业”模式已经破坏了Java EE世界中许多人的大脑。请不要重复.NET land中的错误。

答案 6 :(得分:1)

DTO的主要用例是从Web服务返回数据。在这种情况下,POCO和DTO是等价的。当从Web服务返回时,POCO中的任何行为都将被删除,因此它是否具有行为并不重要。

答案 7 :(得分:0)

TL; DR:

DTO描述状态转移的模式。 POCO没有描述任何内容。这是在OOP中说“对象”的另一种方式。它来自由马丁·福勒(Martin Fowler)创造的POJO(Java),他实际上只是将其描述为“对象”的昵称,因为“对象”不是很性感。

DTO是一种对象模式,用于在相关层之间转移状态。他们可以有行为(即从技术上讲可以是poco),只要该行为不会改变状态即可。例如,它可能具有一种自行序列化的方法。

POCO是一个普通的对象,但是“普通”的含义是它并不特殊。这只是意味着它是一个CLR对象,没有隐式模式。通用术语。它不是与其他框架一起使用的。因此,例如,如果您的POCO的所有属性都具有[JsonProperty]或EF装饰,那么我认为它不是POCO。

下面是一些不同类型的对象模式的示例,以进行比较:

  • 视图模型:用于为视图数据建模。通常具有数据注释以帮助绑定和验证。在MVVM中,它还充当控制器。不仅仅是DTO
  • 值对象:用于表示值
  • 聚合根:用于管理状态和不变式
  • 处理程序:用于响应事件/消息
  • 属性:用作装饰来处理跨领域关注点
  • 服务:用于执行复杂的任务
  • 控制器:用于控制请求和响应的流
  • 工厂:用于配置和/或组装复杂的对象,以在构造函数不够好时使用。还用于决定在运行时需要创建哪些对象。
  • 存储库/ DAO :用于访问数据

这些都是对象,但是请注意,大多数对象通常都与模式相关。因此,您可以将它们称为“对象”,也可以更具体地说明其意图,并按其含义进行称呼。这也是我们拥有设计模式的原因。在一些作品中描述复杂的概念。 DTO是一种模式。聚合根是一种模式,视图模型是一种模式(例如MVC和MVVM)。 POCO不是模式。

POCO没有描述模式。这只是在OOP中引用类/对象的另一种方式。将其视为一个抽象概念;他们可以指任何东西。 IMO,这是一种单向关系,因为一旦对象到达只能清洁地用于一个目的的位置,它就不再是POCO。例如,一旦用装饰标记了您的类以使其可以在某些框架上使用,则它不再是POCO。因此:

  • DTO是POCO
  • POCO不是DTO
  • 视图模型是POCO
  • POCO不是视图模型

在两者之间进行区分的重点是保持模式清晰一致,以免引起关注并导致紧密耦合。例如,如果您有一个具有更改状态方法的业务对象,但还使用EF装饰修饰到地狱,以保存到SQL Server和JsonProperty,以便可以通过API端点发送回该对象。该对象将不能容忍更改,并且可能会被各种属性(例如,UserId,UserPk,UserKey,UserGuid)填充,其中一些标记为不保存到数据库,而另一些标记为不序列化到API端点处的JSON)。

因此,如果您要告诉我某事是DTO,那么我可能会确保除了移动状态外,它从未被用于其他任何用途。如果您告诉我某些东西是视图模型,那么我可能会确保它没有保存到数据库中。如果您告诉我某些东西是域模型,那么我可能会确保它不依赖于域之外的任何东西。但是,如果您告诉我某事是POCO,那么您根本不会告诉我太多。

答案 8 :(得分:-14)

甚至不称他们为DTO。他们称之为模型 ....期间。模特永远不会有行为。我不知道是谁想出了这个愚蠢的术语DTO,但它必须是.NET的东西才是我能想到的。想想MVC中的视图模型,同样的坝**事物,模型用于在服务器端层或线路周期之间传输状态,它们都是模型。包含数据的属性。这些是你通过电线传递的模型。型号,型号型号。就是这样。

我希望DTO这个愚蠢的词语能够脱离我们的词汇量。