Answers:
POCO遵循OOP规则。它应该(但不是必须)具有状态和行为。POCO来自POJO,由Martin Fowler [杜撰故事在这里。他使用术语POJO来使拒绝框架繁重的EJB实现更加性感。POCO应该在.Net中的相同上下文中使用。不要让框架决定对象的设计。
DTO的唯一目的是转移状态,并且不应有任何行为。有关使用此模式的示例,请参见Martin Fowler 对DTO的解释。
区别在于:POCO描述了一种编程方法(老式的面向对象编程),其中DTO是一种模式,用于使用对象“传输数据”。
尽管您可以将POCO像DTO一样对待,但是这样做会冒创建贫血域模型的风险。此外,由于DTO应该被设计为传输数据,而不是代表业务领域的真实结构,因此结构上存在不匹配。这样的结果是DTO往往比您的实际域平坦。
在任何复杂的领域中,创建单独的域POCO并将其转换为DTO几乎总是更好。DDD(域驱动设计)定义了反腐败层(此处是另一个链接,但最好的办法是购买书),这是一个很好的结构,可以使隔离清晰。
因为我已经在博客文章中表达了自己的立场,所以对我来说可能是多余的,但是该文章的最后一段总结了这一点:
因此,总而言之,学习爱POCO,并确保您不会散布任何与DTO相同的错误信息。DTO是简单的数据容器,用于在应用程序的各层之间移动数据。POCO是成熟的业务对象,其一个要求是持久性忽略(没有获取或保存方法)。最后,如果您还没有签出吉米·尼尔森(Jimmy Nilsson)的书,请从您当地的大学图书馆中取书。它具有C#中的示例,是一本好书。
顺便说一句,帕特里克·帕特里克(Patrick)我读了POCO的《生活方式》一文,我完全同意,那是一篇很棒的文章。实际上,这是我推荐的Jimmy Nilsson书中的一部分。我不知道它可以在线获得。他的书确实是我在POCO / DTO /存储库/和其他DDD开发实践中找到的最佳信息来源。
我认为DTO可以是POCO。DTO更多关于对象的使用,而POCO更多关于对象的样式(与体系结构概念脱钩)。
当您谈论域模型/业务逻辑模型内部的POCO时,POCO与DTO有所不同的一个例子是,它很好地表示了您的问题域。您可以在整个应用程序中使用POCO,但这可能会带来一些不良的副作用,例如知识泄漏。例如,DTO是从与UI进行通信的服务层使用的,DTO是数据的平面表示,并且仅用于为UI提供数据,并将更改传达回服务层。服务层负责将DTO的两种方式映射到POCO域对象。
更新 Martin Fowler 表示,这种方法要走很繁重的路,只有在域层和用户界面之间存在严重不匹配的情况下才应采用。
DTO的主要用例是从Web服务返回数据。在这种情况下,POCO和DTO是等效的。从Web服务返回POCO后,POCO中的任何行为都将被删除,因此,是否具有行为并不重要。
这是一般规则:DTO ==邪恶和过度设计的软件的指示器。POCO ==好。“企业”模式破坏了Java EE世界中许多人的大脑。请不要在.NET land中重复该错误。
DTO类用于对来自不同来源的数据进行序列化/反序列化。当您想从源中反序列化对象时,无论是外部源:服务,文件,数据库等。您可能只想使用其中的一部分,但是您想要一种简单的方法将数据反序列化为宾语。之后,将数据复制到要使用的XModel。串行器是一种加载DTO对象的漂亮技术。为什么?您只需要一个函数即可加载(反序列化)对象。
TL; DR:
DTO描述了状态转移的模式。POCO没有描述任何内容。这是在OOP中说“对象”的另一种方式。它来自由马丁·福勒(Martin Fowler)创造的POJO(Java),他从字面上仅将其描述为“对象”的更高级名称,因为“对象”不是很性感。
DTO是一种对象模式,用于在相关层之间转移状态。他们可以有行为(即从技术上讲可以是poco),只要该行为不会使状态发生变化即可。例如,它可能具有序列化自身的方法。
POCO是一个普通的对象,但是“普通”的含义是它并不特殊。这只是意味着它是一个CLR对象,没有隐式模式。通用术语。它不是与其他框架一起使用的。因此[JsonProperty]
,例如,如果您的POCO的所有属性都具有EF装饰,那么我认为它不是POCO。
这里有一些不同种类的对象模式的例子进行比较:
这些都是对象,但请注意,它们中的大多数通常与某个模式相关联。因此,您可以将它们称为“对象”,也可以更具体地说明其意图,并按其含义进行称呼。这也是我们拥有设计模式的原因。在一些作品中描述复杂的概念。DTO是一种模式。聚合根是一个模式,视图模型是一个模式(例如MVC和MVVM)。POCO不是模式。
POCO没有描述模式。这只是在OOP中引用类/对象的另一种方式。将其视为一个抽象概念;他们可以指任何东西。IMO,这是一种单向关系,因为一旦对象到达只能清洁地用于一个目的的位置,它就不再是POCO。例如,一旦用装饰标记了您的类以使其可以在某些框架上使用,它就不再是POCO。因此:
区分两者的重点在于保持模式清晰一致,以免引起关注并导致紧密耦合。例如,如果您有一个具有更改状态方法的业务对象,但还使用EF装饰修饰到地狱,以保存到SQL Server和JsonProperty,以便可以通过API端点发送回该对象。该对象将无法容忍更改,并且可能会随处可见属性的各种变体(例如,UserId,UserPk,UserKey,UserGuid,其中一些标记为不保存到数据库,而另一些标记为不序列化到API端点处的JSON)。
因此,如果您要告诉我的是DTO,那么我可能会确保除了将状态转移之外,它从未被用于其他任何用途。如果您告诉我某些东西是视图模型,那么我可能会确保它没有保存到数据库中。如果您告诉我某些东西是域模型,那么我可能会确保它不依赖于域之外的任何东西。但是,如果您告诉我某事是POCO,那么您根本不会告诉我太多。
甚至不称它们为DTO。他们被称为Models..Period。模型永远不会有行为。我不知道是谁提出了这个愚蠢的术语DTO,但是我所能想到的一定是.NET。考虑一下MVC中的视图模型,同样重要的是,模型用于在服务器层之间或整个线路周期之间传输状态,它们都是模型。带有数据的属性。这些是您通过电线的模型。模型,模型模型。而已。
我希望愚蠢的术语“ DTO”会从我们的词汇中消失。