如何建模和处理演示文稿DTO从复杂的领域模型中抽象出来?

时间:2010-04-11 20:36:05

标签: java architecture spring-mvc n-tier-architecture

您好我正在开发一个需要使用Hibernate处理复杂域模型的应用程序。这个应用程序使用Spring MVC并且在表示层中使用域对象非常混乱,所以我认为我应该使用DTO来往于我的服务层,以便这些匹配我在视图中所需的内容。现在假设我有一个CarLease实体,其属性不是简单的java原语,但它与Make,Model等其他实体组成

    public class CarLease {
        private Make make;
        Private Model model;
        .
        .
        .
    }

大多数属性都是这种方式,并且可以使用jsp视图上的下拉选项来选择它们,每个属性都会将ID发回控制器。

现在考虑一些标准用例:创建,编辑,显示

你将如何建模演示文稿DTO用作表单支持对象以及表示层和服务层之间的通信?

您是否会为每种情况(创建,编辑,显示)创建不同的DTO,您是否会针对复杂属性制作DTO?如果是这样,您将ID转换为实体?

您将如何以及在何处处理验证,DTO /域组装,您将从服务层方法返回什么? (创建,编辑,获取)

正如你所看到的,我现在将把我的视图与域对象分开(非常复杂,有很多我不需要的东西)。但是我很难找到任何真实的例子和最佳实践为了这。我需要从上到下的一些架构指导,请记住,我将使用Spring MVC,以防可能利用你的anwser。

提前感谢。

3 个答案:

答案 0 :(得分:3)

对于它的价值(我正在使用C#.net进行开发 - 但原则应该仍然对您有所帮助)我定义了一堆类型(DTO),我用它来交换业务和数据之间的数据层;每个域对象/实体我有多个类型。这些被定义为简单类。

每个都是在考虑特定任务的情况下构建的,例如:

  • 我有一个轻量级类型,用于填充列表视图(许多“行”但不是很多“列”)。我也有一个相应的集合类型,其中包含任意数量的这些。
  • 我有一个“大”的获取副本,通常具有相关实体的所有属性 - 但只有一个实例。根据实体的大小和复杂程度与使用情况的不同,我可能不止一个;并且还取决于您是想立即返回与实体实例关联的所有数据,还是在以后的请求中延迟加载一些数据。
  • 我通常还为实体提供单独的“保存”(新)和“更新”类型。

每种类型仅用于保存与给定任务相关的信息。 例如,“big”将返回上次修改的日期,但我不希望在我的保存和更新类型中,因为我填充了数据访问层中的那些。

此外,对于我的应用程序,这些类型存在于一个通用程序集中 - 因此它们可以在任何层之间重用,而不仅仅是在业务层和数据层之间。

建筑设计

这种方法没有什么特别之处,它有自己的优点和缺点;究竟是什么以及它们如何影响你将取决于很多事情 - 我猜你的里程会有所不同 - 但它确实很好地服务了我好几年了。

人们经常对“关注点分离”大惊小怪 - 这是一个非常明智的举动;这与DTO的关系在于它们在层(以及服务,组件等)之间进行交换,因此在准确绘制线的位置上总会存在一些模糊性。

我采取的方法是,如果一些信息适合在层之间交换,那么它可能适合在任意数量的层之间进行交换 - 那么为什么不让所有人都可以访问它?如果您只是通过它,它还可以节省重新投射信息。

就复杂性而言 - 有两种处理方式:

  1. 对所有人使用详细/人类可读的命名约定;这些类型让你知道什么是事物;无论有多少都有 - 这就是智能(& docs)的用途。越直观越好。
  2. KISS - 如果可以的话,保持简单;你必须平衡合理的重用和单一责任原则(SRP)。
  3. 您是否会创建主要实体的复杂属性的DTO?

    我发现自己制作DTO是出于以下两个原因之一:

    1. 我知道需要暴露(推送)的数据,而DTO的设计是明智的:它是由我想要公开的数据驱动的。
    2. 拉:消费者知道它想要什么,而DTO旨在满足这些需求。
    3. 因为它们都是在一个通用程序集中定义的,没有一个组件“拥有”它,它有助于你从“域”角度思考而不是以组件为中心思考;在某种程度上,这将影响DTO的设计(平衡重用与SRP)。

      在这两种情况下,制作的DTO都可以根据特定需要安静,或者通用;例如,只有一个int和一个字符串的DTO并不罕见,这是你用来发送到下拉列表的那种东西。

      我发回的大多数DTO集合(从DAL到BL)都是特定于概念的 - 而不是通用的。我通过我提供的构造函数对这些实施非常非常基本的规则:每个arg都是必需的。我不确定这是否回答了您的问题“如何管理装配和验证”。

答案 1 :(得分:1)

服务层应该返回DTO而不是EJB对象的想法主要是EJB3 / JPA之前的想法。在CRUD期间,您通过直接使用模型对象(a.k.a. entities)获得了很多。

然而,当用于性能优化时,您可以从使用DTO中受益,例如,当模型对象过于庞大或者使用某些智能连接来聚合模型数据时,您将获益。

因此,除非您在SOA下进行工程设计,否则我不建议您使用DTO进行CRUD操作。

答案 2 :(得分:1)

您是否考虑过命令查询责任分离(CQRS)原则?简而言之,它是一种架构原则,主张使用单独的组件进行读取和修改操作。

使用发送到域模型的命令完成修改。您的NewCarLeaseDTO看起来像一个命令 - CreateNewCarLeaseCommand。它们包含特定操作所需的所有数据。

另一方面,读取(列表或详细信息)直接在底层数据存储(SQL数据库)上完成。这里有很多可能,从拥有相同的数据存储支持读写部分到通过发布/订阅基础设施连接两个独立的数据存储。

当使用后者(两个商店)的方法来阅读时,很多人(比如Udi Dahan)主张使用所谓的持久性观点。这意味着直接以您的视图可以使用的形式存储数据。在模型更新后同步时完成转换(非规范化)。

如果您想了解更多关于CQRS的信息,我建议您阅读Udi Dahan和Greg Young。