本地 DTO
2004 年 10 月 21 日
如果你一直在关注我的同事 ThoughtBloggers,你会知道似乎 我的一个 fowlbots 熔断了,澳大利亚的阳光显然会把这些瑞典模型烤焦。
Jon 对 数据传输对象 感到厌烦,但这并不是说 DTO 是不好的东西,就像任何模式一样,它们在特定情况下很有用。模式总是包含两个部分:如何和何时。你不仅需要知道如何实现它们,还需要知道何时使用它们以及何时不使用它们。
他确实有道理 - 尽管我只在远程接口的上下文中讨论它们,但我没有在模式本身的描述中重申它们的远程上下文 - 而且我确实遇到过喜欢在非远程情况下使用它们的人。所以这是我弥补的机会。
DTO 被称为数据传输对象,因为它们的全部目的是在昂贵的远程调用中传输数据。它们是实现粗粒度接口的一部分,远程接口为了性能需要这种接口。你不仅在本地上下文中不需要它们,而且它们实际上是有害的,因为粗粒度 API 更难使用,而且你必须完成将数据从你的域或数据源层移动到 DTO 的所有工作。
有些人主张将它们作为 服务层 API 的一部分,因为它们确保服务层客户端不依赖于底层的 域模型。虽然这可能很方便,但我认为它不值得所有这些数据映射的成本。正如我的合作者 Randy Stafford 在 P of EAA 中所说,“不要低估 [使用 DTO] 的成本......它很显著,而且很痛苦 - 也许仅次于对象关系映射的成本和痛苦”。
我听到的另一个论点是,如果你想以后进行分布式部署,可以使用它们。这种推测性的分布式边界正是我用 第一定律 反对的东西。添加远程边界会增加复杂性。因此,我将呼应 Randy 的建议,“从一个本地可调用的服务层开始,其方法签名处理域对象。当你需要时(如果有的话)添加可远程访问性,方法是在你的服务层上放置 远程外观 或让你的服务层对象实现远程接口。”
在某些情况下,使用类似 DTO 的东西是有用的,例如,当你的表示层中的模型与底层域模型之间存在重大差异时。在这种情况下,创建特定于表示层的门面/网关是有意义的,它从域模型映射并呈现一个对表示层友好的接口。它与 表示模型 很好地契合。我希望在新的卷中更多地谈论这个问题。这样做是值得的,但只有对存在这种差异的屏幕这样做才值得(在这种情况下,这不是额外的工作,因为你无论如何都必须在屏幕中这样做。)
更新:Thibaut Barrère 提醒了我本地 DTO 的另一个用途,即在多线程应用程序中隔离之间进行通信。处理多线程的一种好方法是将你的应用程序划分为隔离区域,每个区域只有一个线程在其中运行。这消除了该区域内对并发控制的需求。如果你需要在这些隔离区域之间进行通信,那么使用消息队列,并将 DTO 作为消息来传输信息。