第5章分布式系统模式 Data Transfer Object(数据传输对象)

正在设计一个分布式应用程序,为了满足单个客户端请求,您发现自己对一个远程接口发出了多个调用,而这些调用所增加的响应时间超出了可接受的程度。

影响因素

在与远程对象通信时,请考虑下列需要权衡的因素:

  • 远程调用(那些必须跨越网络的调用)速度缓慢。虽然许多远程调用框架可以隐藏进行远程调用的复杂性,但是它们不能消除发生通信所需的步骤。例如,必须先找到 远程对象位置,而且建立与远程计算机的连接,然后才能将数据串行化为字节流,然后可能进行加密,最后才能将其传输到远程计算机。
  • 在 考虑网络性能时,必须同时考虑滞后时间和吞吐量。简单地说,"滞后时间"描述了数据的首字节到达目的地之前所经过的时间。"吞吐量"描述了在某个时间段 (例如 1 秒)内通过网络发送的数据字节数。在基于 IP 路由的现代网络(例如 Internet)中,滞后时间可以是比吞吐量更大的因素。这意味着,传输 10 字节数据所用的时间可能几乎等于传输 1,000 字节数据所用的时间。在使用无连接协议(如 HTTP)时,此效果尤其明显。通常,网络速度越快可以使吞吐量得以增加,但是,要减少滞后时间则会更加困难。
  • 在 设计对象接口时,好的做法是将大量信息隐藏在对象内,并提供一组细粒度方法来访问和操作该信息。"细粒度"意味着每个方法都应该负责单个的、相当小的和基 本的功能单位。此方法简化了编程,并提供了对对象内部的更佳抽象,从而增加了重用的可能性。必须根据以下事实对此进行平衡取舍:使用较细粒度的方法意味着 需要调用更多的方法才能执行高级别的任务。通常,在同一进程内调用方法时,这些额外函数调用的开销是可接受的;但是,在跨进程和网络边界调用这些方法时, 开销可能变得难以接受。
  • 避免远程调用中固有的滞后时间问题的最佳方法是进行更少的调用,并让每个调用传递更多的 数据。做到这一点的一种方法是,使用长参数列表来声明远程方法。这样,客户端就可以在单个调用中将更多的信息传递给远程组件。但是,这样做会使针对此接口 的编程容易出错,因为程序很可能仅按调用语句中的位置来调用外部方法的参数。例如,如果远程方法接受 10 个字符串参数,则开发人员很容易按错误顺序传递参数。编译器将无法检测到这样的错误。
  • 长参数列表无助于从远程调用向客户端返回更多的信息,因为大多数的编程语言将方法调用的返回类型限制为单个参数。而巧合的是,在传输大多数数据时通常需要返回较多信息。例如,许多用户接口传输少量的信息,却希望返回大量结果数据。

解决方案

创 建一个数据传输对象 (DTO),用该对象包含远程调用所需要的所有数据。修改远程方法签名,以便将 DTO 作为单个参数接受,并将单个 DTO 参数返回给客户端。在调用方应用程序收到 DTO 并将其作为本地对象存储之后,应用程序可以分别对 DTO 发出一系列单独的过程调用,而不会引发远程调用开销。Martin Fowler Patterns of Enterprise Application Architecture [Fowler03] 中对此模式进行了说明。

下图显示客户端应用程序如何进行一系列远程调用以检索客户名称的各个元素。

图 1:没有 DTO 的远程调用

DTO 允许远程对象在单个远程调用中将整个客户名称返回给客户端。在此示例中,这样做将使调用次数从 4 次减为 1 次。客户端进行单个调用,然后在本地与 DTO 交互,而不用进行多次远程调用(见图 2)。

图 2:通过使用 DTO 减少调用次数

DTO 是一组需要跨进程或网络边界传输的聚合数据的简单容器。它不应该包含业务逻辑,并将其行为限制为诸如内部一致性检查和基本验证之类的活动。注意,不要因实现这些方法而导致 DTO 依赖于任何新类。

在设计数据传输对象时,您有两种主要选择:使用一般集合;或使用显式的 getter 和 setter 方法创建自定义对象。

一 般集合的优点是,只需要一个类,就可以在整个应用程序中满足任何数据传输目的。此外,集合类(例如,简单数组或散列图)内置于几乎所有语言库中,因此您根 本不必编写新类的代码。对 DTO 使用集合对象的主要缺点是,客户端必须按位置序号(在简单数组的情况下)或元素名称(在键控集合的情况下)访问集合内的字段。此外,集合存储的是同一类型 (通常是最一般的 Object 类型)的项目,这可以导致在编译时无法检测到的微妙但致命的编码错误。

如果为每个 DTO 创建自定义类,则可以提供与任何其他对象完全一样的、客户端应用程序可访问的强类型对象,这样的对象可以提供编译时检查,并支持代码编辑器功能(如 Microsoft® IntelliSense® 技术)。主要缺点是,如果应用程序发出许多远程调用,则您最终可能必须编写大量类的代码。

许多方法试图将这两种方法的优点结合在一起。第 一种方法是代码生成技术,该技术可以生成脱离现有元数据(如可扩展标记语言 (XML) 架构)的自定义 DTO 类的源代码。第二种方法是提供更强大的集合,尽管它是一般的集合,但它将关系和数据类型信息与原始数据存储在一起。Microsoft ADO.NET DataSet 支持这两种方法(请参阅在 .NET 中使用 DataSet 实现 Data Transfer Object)。

有 了 DTO 类以后,需要用数据填充它。大多数情况下,DTO 内的数据来自多个域对象。因为 DTO 没有行为,因此它不能从域对象提取数据。这是对的,因为如果让 DTO 不知道域对象,您就可以在不同的上下文中重用 DTO。同样,您不希望域对象知道 DTO,因为这可能意味着更改 DTO 将要求更改域逻辑中的代码,这将导致大量维护任务。

最佳的解决方案是使用 Assembler 模式 [Fowler03],该模式可以用业务对象创建 DTO 或者相反 Assembler Mapper 模式的专门实例,在 Patterns of Enterprise Application Architecture [Fowler03] 中也提到过它。

图 3:使用 Assembler 将数据加载到 DTO 中

Assembler 的关键特征是 DTO 和域对象不相互依赖。这就消除了这两种对象的相互影响。不利方面是 Assembler 同时依赖于 DTO 和域对象。对这些类的任何更改都可能导致必须更改 Assembler 类。

测试考虑事项

DTO 是简单对象,它不应该包含需要测试的任何业务逻辑。但是,您确实需要测试每个 DTO 的数据聚合。每个 DTO 可能需要测试,也可能不需要,这取决于您的序列化机制。如果序列化是框架的一部分,则只需要测试一个 DTO。如果不是这样,请使用一般的反射机制,这样就不需要测试每个 DTO 的序列化。

DTO 还对远程函数的可测试性有好处。通过使远程方法的结果能够在对象实例中使用,可以轻松地将此数据传递到测试模块,或将其与所需结果进行比较。

安全考虑事项

理想情况下,应该先筛选和验证从不可靠的来源获得的数据(如来自 Web 页的用户输入),然后将其置于 DTO 中。通过这样做,就可以认为 DTO 中的数据是相对安全的,从而简化了将来与 DTO 的交互。

接 收 DTO 的进程和关联用户的安全凭据也是值得注意的。DTO 通常包含从许多不同来源聚集在一起的大量信息。您是否已授权 DTO 的所有用户访问 DTO 所包含的所有信息?确保用户已得到授权的最佳方法是仅使用用户安全凭据所允许的特定数据填充 DTO。努力避免让 DTO 负责自己的安全性。这将增加 DTO 对其他类的依赖数,这意味着必须将这些类部署到使用 DTO 的所有节点。这还会将安全性功能分散到更多类中,从而增大了安全风险,并对灵活性和可维护性产生负面影响。

结果上下文

Data Transfer Object 具有下列优缺点:

优点

  • 减少了远程调用次数。通过在单个远程调用中传输更多的数据,应用程序可以减少远程调用次数。
  • 提高了性能。远程调用可以使应用程序的运行速度大大降低。减少调用次数是提高性能的最佳方法之一。在大多数方案中,传输大量数据的远程调用所用的时间与仅传输少量数据的调用所用的时间几乎相等。
  • 隐藏内部情况。在单个调用中来回传递更多的数据,还可以更有效地将远程应用程序的内部情况隐藏在粗粒度接口的背后。这就是使用 Remote Facade 模式 [Fowler03] 的主要原因。
  • 发现业务对象。在一些情况下,定义 DTO 有助于发现有意义的业务对象。在创建用作 DTO 的自定义类时,您通常会注意到作为一组凝聚性信息而显示给用户或另一个系统的元素分组。通常,这些分组用作描述应用程序所处理的业务域的对象的有用原型。
  • 可测试性。将所有参数封装到可序列化对象中可以提高可测试性。例如,可以从 XML 文件中读取 DTO,并调用远程函数以测试它们。同样,可以轻松地将结果再序列化为 XML 格式,并将 XML 文档与所需结果进行比较,而不必创建冗长的比较脚本。

缺点

  • 可能需要太多的类。如果选择了使用强类型的 DTO,则可能必须为每个远程方法创建一个(如果考虑返回值,则为两个)DTO。即使在粗粒度接口中,这也可能导致大量的类。编写如此数量的类的代码并管理这些类会是很困难的。使用自动代码生成可以在一定程度上缓解此问题。
  • 增加计算量。如 果将服务器上的一种数据格式转换为可以跨网络传输的字节流,并在客户端应用程序内转换回对象格式,可以带来相当大的开销。通常,需要将来自多个源的数据聚 合到服务器上的单个 DTO 中。要提高通过网络进行远程调用的效率,必须在任一端执行其他计算,才能聚合和串行化信息。
  • 增加编码工作量。可以用一行代码完成将参数传递到方法的操作。使用 DTO 要求实例化新对象,并为每个参数调用 setters 和 getters。编写此代码可能是很乏味的。
时间: 2024-10-06 00:28:12

第5章分布式系统模式 Data Transfer Object(数据传输对象)的相关文章

第5章分布式系统模式 在 .NET 中使用 DataSet 实现 Data Transfer Object

要在 .NET Framework 中实现分布式应用程序.客户端应用程序需要显示一个窗体,该窗体要求对 ASP.NET Web Service 进行多个调用以满足单个用户请求.基于性能方面的考虑,我们发现,进行多个调用会降低应用程序性能.为了提高性能,需要通过对 Web Service 进行一次调用就能检索到用户请求所需的所有数据. 背景信息 注意:以下是在 .NET 中使用类型化 DataSet 实现 Data Transfer Object 中所描述的同一个示例应用程序. 下面是一个简化的

第5章分布式系统模式

在当今的互联世界中,越来越多的企业应用程序跨多个服务器分布和运行.连接到远程数据源和 Web Service,并可通过 Internet 访问.分布式计算功能强大,但也并非没有面临挑战.网络在本质上并不可靠,同本地的进程间通信相比,与远程服务器的通信速度较慢.另外,同时在多台计算机 上运行一个程序可能会导致许多并发和同步问题. 基于实例的协作和基于服务的协议 按照 Business Component Factory(业务组件工厂)的说,分布式计算可以基于两个截然不同的体系结构样式: 基于实例的

Java DTO(data transfer object)的理解

首先明白springboot每层 model层 model层即数据库实体层,也被称为entity层,pojo层. 一般数据库一张表对应一个实体类,类属性同表字段一一对应. Model层是数据层: TableName是对数据表实体的映射: Criteria传输前台数据 DTO 传输类间数据 dao层 dao层即数据持久层,也被称为mapper层. dao层的作用为访问数据库,向数据库发送sql语句,完成数据的增删改查任务. service层 service层即业务逻辑层. service层的作用为

贫血模型;DTO:数据传输对象(Data Transfer Object);AutoMapper ;Domain Model(领域模型);DDD(领域驱动设计)

====================== 我自己的理解 ========================== 一:  DTO  我自己的理解,就是 比如你有一个类,跟数据库的table表结构一模一样,主键外键什么的都有,但是这个 model类,你返回数据到 UI层的时候,有些数据是不用的,你就得自己new一个新类出来,新的类从旧的类里面拿值,然后给别人用的就是新的类别,有点类似于我们做接口给android手机用一样的,数据库的类和接口用的类,很相似,但是东西少了的很多,这个新的类(缺胳膊断腿

第5章分布式系统模式 使用服务器激活对象通过 .NET Remoting 实现 Broker

正在使用 Microsoft? .NET Framework 构建一个需要使用分布式对象的应用程序.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上.应用程序不需要您显式控制远程对象的生存期. 关于 .NET Remoting 的背景信息 远 程处理使用对象引用来进行客户端和服务器之间的通信.在服务器激活情况下,客户端使用远程处理基础结构 (Activator.GetO

第5章分布式系统模式 Broker(代理程序)

许多复杂的软件系统运行在多个处理器或分布式计算机上.将软件分布在多台计算机上的原因有多种,例如: 分布式系统可以利用多个 CPU 或一群低成本计算机的计算能力. 某个软件可能仅在特定计算机上可用. 出于安全考虑,软件的各部分可能必须运行在不同的网段上. 一些服务可能是由业务合作伙伴提供的,并且只能通过 Internet 进行访问. 但是,实现分布式系统是不容易的,因为您必须处理诸如并发性.跨平台连接和不可靠网络连接之类的问题. 影响因素 在构建分布式系统时,必须协调下列影响因素: 虽 然分布式系

第5章分布式系统模式 使用客户端激活对象通过 .NET Remoting 实现 Broker

正在 .NET 中构建一个需要使用分布式对象的应用程序,并且分布式对象的生存期由客户端控制.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算 机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上. 实现策略 这 种模式为在 .NET Remoting 中实现客户端激活对象提供了两种实现方式.客户端激活对象 (CAO) 和服务器激活对象 (SAO) 之间的主要区别在于,是什么控制着远程对象的生存期.在使用 CAO 的情况下

第5章分布式系统模式 Singleton

上下文 在某些情况下,特定类型的数据需要提供给应用程序中的其他所有对象使用.在大多数情况下,这种类型的数据在系统中还是唯一的.例如,用户界面只能有一个所有应用程序必须访问的鼠标指针.同样,企业解决方案可能用单网关对象作为接口来管理与特定旧系统的连接. 影响因素 以下因素影响这种情况中的系统,在考虑上述问题的解决方案时必须协调这些影响因素: 很多编程语言(例如 Microsoft Visual Basic® 6.0 版或 C++)都支持全局对象的定义.这些对象位于命名空间的根部,应用程序中所有对象

使用Micrisoft.net设计方案 第二章组织模式

模式不仅依赖于它所包含的更小模式,同时也依赖包含它的更大的模式.它是描述复杂软件的系统方法. 本章的目标是让我们了解以下问题: 1.如何标识模式与模式的关系 2.如何把模式组织成模式集合 3.如何采用不同抽象级别去划分模式 4.如何使用模式解决系统中涉及到的各个方面 5.如何用模式描述解决方案 模式与模式 模式能够描述关系.采用面向对象设计的软件都是有类组成,如果抛开类与类间的关系,模式将什么问题也不能解决.模式把一组类组织成便于管理的模式集合. 我们设计系统时,会发现使用的模式比使用的类都多,