DTO 和 POCO(或 POJO)有什么区别

        DTO 和 POCO(或 POJO)有什么区别

原文链接:https://ardalis.com/dto-or-poco/

作者:Ardalis Steve

在讨论 .NET 和 C# 中的软件开发时经常出现的两个术语是 DTO 和 POCO。一些开发人员交替使用这些术语。那么,DTO 和 POCO 之间有什么区别?首先,让我们定义每个术语。

数据传输对象 (DTO)

DTO 是“数据传输对象”。它是一个目的是传输数据的对象。根据定义,DTO 应该只包含数据,而不是逻辑或行为。如果 DTO 包含逻辑,则它不是 DTO。但是等等,什么是“逻辑”或“行为”?

通常,逻辑和行为是指类型上的方法。在 C# 中,DTO 应该只有属性,并且这些属性应该只获取和设置数据,而不是验证数据或对其执行其他操作。

属性和数据注释呢?

将元数据添加到 DTO 以使其支持模型验证或类似目的并不罕见。这些属性不会向 DTO 本身添加任何行为,而是促进系统中其他地方的行为。因此,它们不会违反 DTO 不应包含任何行为的“规则”。

ViewModel、API 模型等呢?

DTO 一词非常含糊。它只是说一个对象只包含数据,而不是行为。它没有说明其预期用途。在许多架构中,DTO 可以充当多种角色。例如,在大多数具有支持绑定到数据类型的视图的 MVC 架构中,DTO 用于将数据传递和绑定到视图。这些 DTO 通常称为 ViewModel,理想情况下它们应该没有行为,只有按照 View 期望的格式设置数据。因此,在这种情况下,ViewModel 是一种特定类型的 DTO。但是,要小心。然后你不能得出所有 ViewModel 都是 DTO 的结论,因为在MVVM 架构中[1]ViewModel 通常包含大量行为。因此,在做出任何广泛假设之前考虑上下文非常重要。即使在 MVC 应用程序中,有时逻辑也会添加到 ViewModel 中,这样它们就不再是 DTO。


DTO 和 ViewModels 

只要可能,请根据其预期用途命名您的 DTO。命名一个类FooDTO并没有说明在应用程序的体系结构中应该如何或在何处使用该类型。相反,更喜欢像FooViewModel.

C# 中的示例 DTO

下面是 C# 中的示例 DTO 对象:

public class ProductViewModel
{public int ProductId { get; set; }public string Name { get; set; }public string Description { get; set; }public string ImageUrl { get; set; }public decimal UnitPrice { get; set; }
}

封装和数据传输对象

封装是面向对象设计的重要原则。但它不适用于 DTO。封装用于防止类的协作者过于依赖有关类如何执行其操作或存储其数据的特定实现细节。由于 DTO 没有操作或行为,并且应该没有隐藏状态,因此它们不需要封装。不要通过使用私有 setter 或试图让你的 DTO 表现得像不可变的值对象,从而使你的生活变得更艰难。您的 DTO 应该易于创建、易于编写和易于阅读。他们应该支持序列化而不需要任何自定义工作来支持它。

字段或属性

既然 DTO 不关心封装,为什么要使用属性呢?为什么不只使用字段?您可以使用任何一种,但某些序列化框架仅适用于属性。我通常使用属性,因为这是 C# 中的约定,但是如果您更喜欢公共字段或有为什么它们更可取的设计原因,您当然可以使用它们。无论您选择哪种方式,我都会尝试在您的应用程序中使用字段或属性时保持一致。有利弊的一些讨论在这里[3]

不变性和记录类型

不变性在软件开发中有很多好处,并且在 DTO 中也是一个有用的特性。Jimmy Bogard 写过关于尝试在 DTO 中实现不变性的文章[4],而Mark Seeman[5]在对该文章的评论中(以及在上面的堆栈溢出问题中)采用了相反的方法。就我个人而言,我通常不会将 DTO 构建为不可变的,正如您从上面显示的示例中看到的那样。不过,这可能会随着C# 9 及其引入的记录类型而改变[6]。顺便说一下,您可能会看到的另一个首字母缩写词是数据传输记录或 DTR。这是使用 C# 9 定义 DTR 的一种方法:

public record ProductDTO(int Id, string Name, string Description);

当使用记录类型和上述位置声明时,会为您生成一个构造函数,其顺序与声明相同。因此,您将使用以下语法创建此 DTR:

var dto = new ProductDTO(1, "devBetter Membership", "A one-year subscription to devBetter.com");

或者,您可以以更传统的方式定义属性并在构造函数中设置它们。另一个新特性是 init-only 属性,它支持在创建时初始化,但在其他方面是只读的,保持记录不可变。一个例子:

public record ProductDTO
{public int Id { get; init; }public string Name { get; init; }
}// usage
var dto = new ProductDTO { Id = 1, Name = "some name" };

C# 记录类型在使用位置声明时无需任何特殊努力即可支持序列化。如果您创建自己的自定义构造函数,则可能需要向序列化程序提供一些提示。随着 C# 9、.NET 5 和记录类型越来越流行,我希望能经常将它们用于 DTR。

普通旧 CLR 对象或普通旧 C# 对象 (POCO)

一个普通的旧 CLR/C# 对象是一个 POCO。Java 有普通的旧 Java 对象,或 POJO。你真的可以将这些统称为“Plain Old Objects”,但我猜有人不喜欢产生的首字母缩略词。那么,一个对象“老旧”是什么意思呢?基本上,它不依赖于特定的框架或库来运行。一个普通的旧对象可以在您的应用程序或测试中的任何地方实例化,并且不需要涉及特定的数据库或第三方框架来运行。

通过展示反例来演示 POCO 是最简单的。以下类依赖于一些引用数据库的静态方法,这使得该类完全依赖于数据库的存在才能发挥作用。它还继承自(组成的)第三方持久性框架中定义的类型。

public class Product : DataObject<Product>
{public Product(int id){Id = id;InitializeFromDatabase();}private void InitializeFromDatabase(){DataHelpers.LoadFromDatabase(this);}public int Id { get; private set; }// other properties and methods
}

给定这个类定义,假设您想对 上的某个方法进行单元测试Product。你编写测试,你做的第一件事就是实例化一个新的实例,Product这样你就可以调用它的方法。并且您的测试立即失败,因为您尚未为DataHelpers.LoadFromDatabase要使用的方法配置连接字符串。这是Active Record 模式的[7]一个例子,它可以使单元测试变得更加困难。此类不是Persistence Ignorant (PI),[8]因为它的持久性直接融入到类本身中,并且该类需要从与持久性相关的基类继承。POCO 的一个特点是它们往往对持久性一无所知,或者至少比 Active Record 等替代方法更是如此。

一个示例 POCO

下面是一个产品的普通旧 C# 对象示例。

public class Product
{public Product(int id){Id = id;}private Product(){// required for EF}public int Id { get; private set; }// other properties and methods
}

这个Product类是一个 POCO,因为它不依赖第三方的行为框架,尤其是持久化行为。它不需要基类,尤其是另一个库中的基类。它与静态助手没有任何紧密耦合。它可以在任何地方轻松实例化。它比前面的示例更不了解持久性,但它并非完全不了解持久性,因为它有一个无用的私有构造函数声明。正如您从评论中看到的那样,私有无参数构造函数之所以存在,是因为实体框架在从持久性读取类时需要它来实例化类。

为了论证起见,假设这两个Product类都包含除了显示的构造函数和属性之外的具有行为的方法。这些可以在应用程序中用作DDD 实体[9],对系统内产品的状态和行为进行建模。

POCO 和 DTO

好的,所以我们已经看到 DTO 只是一个数据传输对象,而 POCO 是一个普通的旧 C#(或 CLR)对象。但是它们之间的关系是什么,为什么开发人员经常混淆这两个术语?除了首字母缩略词的相似性之外,最大的因素可能是所有 DTO 都是(或应该是)POCO。

请记住,DTO 的唯一目的是尽可能简单地传输数据。它们应该易于创建、阅读和编写。它们对第三方框架中定义的特殊基类的任何依赖或将它们与某些行为紧密耦合的静态调用都会破坏使类成为 DTO 的规则。为了成为 DTO,类必须是 POCO。所有 DTO 都是 POCO。

DTO 和 POCO 维恩图

如果反过来也成立,那么我们可以说这两个术语是等价的。但我们知道事实并非如此。在前面的代码示例中,Product使用 Entity Framework 的实体具有私有的 setter 和行为,使其无法成为 DTO。但正如我们所见,它是 POCO 的一个很好的例子。因此,虽然所有 DTO 都是 POCO,但并非所有 POCO 都是 DTO。

References

[1] MVVM 架构中: https://en.wikipedia.org/wiki/Model–view–viewmodel 

[2]: https://ardalis.com/static/ef316c071c0c70148e4b0008830eeae1/d52e5/dto-viewmodel-venn.png
[3] 在这里: https://stackoverflow.com/questions/10831314/dtos-properties-or-fields
[4] Jimmy Bogard 写过关于尝试在 DTO 中实现不变性的文章: https://jimmybogard.com/immutability-in-dtos/
[5] Mark Seeman: http://blog.ploeh.dk/
[6] C# 9 及其引入的记录类型而改变: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
[7] Active Record 模式的: https://www.martinfowler.com/eaaCatalog/activeRecord.html
[8] Persistence Ignorant (PI),: https://deviq.com/principles/persistence-ignorance
[9] DDD 实体: 

https://deviq.com/domain-driven-design/entity https://ardalis.com/static/517f68e51029cdcba6b2d49ca477b863/7fee5/dto-poco-venn.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/300056.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx server之Nginx作为反向代理服务器

2019独角兽企业重金招聘Python工程师标准>>> 一&#xff1a;Nginx介绍 1.Nginx简介&#xff1a;nginx [engine x]是一个俄罗斯人编写的HTTP和反向代理服务器&#xff0c;另外它也可以作为邮件代理服务器。 它已经在众多流量很大的俄罗斯网站上使用了很长时间&#x…

为什么现在老师这么难,值得大家深思

致各位老师不知不觉&#xff0c;顶级教师圈已经陪伴大家走过3个月的时光。我们每天为教师们推送教育资讯&#xff0c;得到了许多关心和支持。为了感谢各位教师们的支持和鼓励&#xff0c;顶级教师圈今日特举办限时资源福利活动。我们精心整理了100G海量教学资源&#xff0c;包含…

学计算机要买什么样的电脑,大学开学要买电脑吗?又要买什么样的电脑?看准这些再买也不迟!...

电脑是我们生活中重要的通讯工具&#xff0c;方便了我们学习办公、工作设计、娱乐游戏&#xff0c;我们也越来越依赖电脑处理不同的事情&#xff0c;尤其是现在的开学季&#xff0c;很多准大学生都准备给自己购置一台电脑&#xff0c;但是由于自己不懂&#xff0c;买了怕被坑&a…

如果格局决定人生,那到底什么决定了格局

全世界只有3.14 %的人关注了青少年数学之旅真正决定人与人之间的差距的&#xff0c;其实是我们对事物的见识与内心的格局&#xff0c;见识的深浅决定人生的深浅&#xff0c;格局的大小决定了人生之路是宽是窄。今天给大家推荐几个有深度、有想法的公众号&#xff0c;希望能够给…

海尔微型计算机一键还原怎么操作,教你电脑一键还原怎么操作

当系统使用的时间久了&#xff0c;出现了不好修复的问题&#xff0c;可使用电脑的一键还原来解决。但一些用户不知电脑一键还原怎么操作呢?其实方法并不难&#xff0c;有需要的用户&#xff0c;请来看看下面的步骤吧一键还原又叫做一键恢复&#xff0c;计算机系统出现问题时就…

我从大厂面试中学到的关于 C# 的知识

我从工作面试中学到的关于 C# 的知识原文链接&#xff1a;https://michaelscodingspot.com/what-i-learned-about-c-from-job-interviews/作者&#xff1a;Michael Shpilt我最近参加了一些最大的科技公司的一系列工作面试。在没有透露姓名的情况下&#xff0c;我得到了世界排名…

深入浅出自定义标签(二)生成javascript

自从写了深入浅出自定义标签(一)入门之后一直没有得出时间继续写,正好这次项目中用到"自定义标签",这次的用途是通过Session中的存储的相关功能点的List,进行迭代生成javascript脚本,在前台通过javascript生成树桩结构所有的页面元素都是Html,包括javascript所以生成…

曾凭一己之力推动物理学发展,是清华大学最年轻教授,世界却欠他一个诺贝尔奖!...

全世界只有3.14 %的人关注了青少年数学之旅说起中国最牛的科学家&#xff0c;大家可能都会想起钱学森。钱学森被美国称为“一个人抵五个师”并阻止他回国的故事&#xff0c;几乎家喻户晓。钱学森但事实上&#xff0c;在中国近代&#xff0c;也有一个科学大牛&#xff0c;曾被美…

SharpDeveloeper开发ASP.NET MVC汗流浃背

今天好不容易休息了一天&#xff0c;上网狂了一圈&#xff0c;突然想起了以前的一个轻量级的开发工具“SharpDeveloper”&#xff0c;于是就下载试着来开发一下ASP.NET&#xff0c;但是老魏没有想到的是&#xff0c;虽然官方提供了对ASP.NET MVC的支持&#xff0c;但是实际开发…

Vue 2升级 Vue 3初探小细节

【导读】嗯&#xff0c;偶尔看看学习Vue 3技能啦&#xff0c;此前用过Vue 2做过一点东西&#xff0c;Vue 3已面世一段时间&#xff0c;于是乎&#xff0c;我来看看所遇到的问题是否在Vue 3中得到解决首先&#xff0c;我们来讲讲一个例子在Vue 2中的实现&#xff0c;举个栗子吧&…

计算机竞赛游戏探险岛,冒险岛2五大全新团本综合分析

随着新版本的到来&#xff0c;这次推出了两个混沌团本&#xff0c;分别是影子军团祭坛、月光船长要塞。三个10人新团本&#xff0c;分别是迷宫集会堂、路贝里斯克、不灭神殿。混沌团本可以掉落橙装&#xff0c;新团本则可以掉落专属武器。影子军团祭坛是我们的两大混沌本之一&a…

薛定谔的猫——.NET 4.1 中的新基类,开源Preview中

前言&#xff1a; 昨天一如既往地登上forums.asp.net答帖子&#xff0c;却被上面的一条滚动新闻雷到了&#xff1a; .NET 4.1 Preview - New Base Class Library (BCL) Extension Methods - RFC 因为考虑到April 1st的关系&#xff0c;这是Scott Hanselman给大家开的玩笑&…

史上最硬核文科生,擅长解决数学难题,却视考试成为终生噩梦

全世界只有3.14 %的人关注了青少年数学之旅“数学存在的价值&#xff0c;不只是为了生活上的应用&#xff0c;它不应沦为供工程、商业应用的工具&#xff0c;数学的突破仍需要不断地去突破现有格局。”——节选自《数学之旅 闪耀人类的54个数学家》他是一位浪漫的法国人&#…

胡晓曼:MindSpore 开源运营与治理 | DEV. Together 2021 中国开发者生态峰会

内容来源&#xff1a;2021 年 6 月 5 日&#xff0c;由 SegmentFault 思否主办的 2021 中国开发者生态峰会圆满落幕。会上&#xff0c;华为 MindSpore 运营总监胡晓曼发表了主题为《MindSpore 开源运营与治理》的演讲。分享嘉宾&#xff1a;胡晓曼&#xff0c;华为 MindSpore 运…

C# 语言特性

Codeusing System;using System.Collections.Generic;using System.Text;namespace InterfaceShadow{ interface ISomeInterface { void DoSomething(); } class Class1 : ISomeInterface { #region ISomeInterface 成员 public void DoSo…

如何掌握C#的核心技术

如何掌握C#的核心技术原图来自网络&#xff0c;如有侵权&#xff0c;请联系小编删除。引子前不久看到一个段子&#xff0c;某年宁波交警引进人脸识别技术抓拍行人闯红灯&#xff0c;结果一天下来被发现闯红灯次数最多的是珠海女子董小姐&#xff0c;日闯红灯3000多次。宁波交警…

怪咖发明家,乔布斯给了他四亿,他没要,转身靠发明救了10亿人。

全世界只有3.14 %的人关注了青少年数学之旅提到乔布斯&#xff0c;大家会想到什么呢&#xff1f;苹果公司创始人&#xff1f;iPhone手机&#xff1f;iPad?人生赢家&#xff1f;不过大家肯定没有想到乔布斯也有吃瘪的时候&#xff1a;有一次&#xff0c;乔布斯对电动平衡车赛格…

祝贺|合肥.NET俱乐部第二期技术沙龙活动圆满成功

热烈祝贺合肥.NET俱乐部第二期技术沙龙圆满成功&#xff0c;感恩参与活动的每一位小伙伴&#xff01;正是因为有你们才促成了这次聚会的成功。现对此次活动进行简单回顾并附上精彩的活动图片&#xff0c;每一位参与活动者名单&#xff0c;以及此次活动讲师分享的PPT供大家学习下…

几个常用的JS代码.

//函数列表function PostCookie(cookieName) { var expdate new Date(); expdate.setTime(expdate.getTime() 604800000); document.cookiecookieName";expires"expdate.toGMTString()";path /;domain.52z.com"; }//用于产生随机轮转广告 i 随机个…

SQL中合并多行记录的方法总汇

SQL中合并多行记录的方法总汇——前几天还在抱怨&#xff1a;sql只有sum(数值)&#xff0c;不能sum(字符串)——如果不是分组统计&#xff0c;用select values values , value也是可以的——但是如果是分组sum(字符串)&#xff0c;肯定不行了&#xff01;——下面是用函数实…