代码之家  ›  专栏  ›  技术社区  ›  sma

视图层中的DTO或域模型对象?

  •  49
  • sma  · 技术社区  · 14 年前

    我知道这可能是一个古老的问题,但更好的做法是什么?在应用程序的所有层中使用域模型对象,甚至在JSP上直接将值绑定到它们(我使用的是JSF)。或者将域模型对象转换为DAO或服务层中的DTO,并将轻量级DTO发送到表示层。

    我被告知使用DTO毫无意义,因为对数据库的更改将导致对所有DTO的更改,而在任何地方使用模型对象只需要对受影响的模型对象进行更改。然而,DTO的易用性和轻量级似乎超过了这一点。

    我应该注意,我的应用程序使用Hibernate模型对象并使用自己自定义创建的模型对象(意味着不绑定到任何DB会话,总是分离)。上面的任何一个场景对严格的模型对象模式更有利吗?使用Hibernate对于延迟初始化异常来说是一个巨大的pita。

    我正在编辑这个问题,希望进一步讨论(不确定我是否做得对):

    我对模型对象的问题是它们根本不灵活。下面的一条注释指出,应该设计应用程序,以便模型对象可以在所有层中使用。为什么?如果一个用户想要一个荒谬的功能,我是否应该告诉他们,“好吧,这不适用于模型对象”?

    简单明了,有时候模型对象不起作用。您可能有:

    public class Teacher {
        List<Student> students;
        [tons of other Teacher-related fields]
    }
    public class Student {
        double gpa;
       [tons of other Student-related fields]
    }
    

    但也许你不需要这些信息。你只需要知道老师的姓,今年他们教的学生人数,以及所有学生的平均绩点。在这种情况下你会怎么做?检索完整的教师信息和学生关系,然后您的代码在学生列表上计数,然后计算出里面所有GPA的总平均值?这似乎比简单地用'string lastname'、'int numstitutes'和'double combinedgpa'创建DTO更费劲;

    听起来好像我已经决定了这些,但是我还没有在一个应用程序中工作,在这个应用程序中模型对象可以在每个实例中被完全地使用。常规的现实世界应用程序,以及异常的用户需求,并不能以这种方式工作。

    8 回复  |  直到 7 年前
        1
  •  33
  •   srmark    13 年前

    它实际上取决于应用程序的复杂性。将域对象混合到视图层中有两个可能的含义:

    1. 您将尝试修改域对象以适应视图层中需要的内容。
    2. 您的视图层将包含额外的复杂性,这是由于域对象提供的内容与视图真正需要的内容不匹配造成的。您可能无法绕过这种复杂性,但它可能不属于视图层。

    如果域对象很简单,视图也很少,那么跳过DTO可能是最简单的事情。

    另一方面,如果您的域模型可能会演变并变得复杂,并且您的视图可能是多个且多样的,那么拥有特定于视图的对象可能是一个好主意。在MVC世界中,使用视图模型是很常见的,对我来说很有意义。

        2
  •  8
  •   Igor Zevaka    14 年前

    对域对象的另一个投票。就领域驱动设计而言,领域模型是王道,应尽可能使用。应用程序的设计应使大多数层(BAR基础结构层)可以使用域对象。

    我认为DTO只在需要序列化对象的地方有用。如果没有传输线或不兼容的体系结构,我不会使用它们。DTO模式对于将串行化保持在域对象之外很有用。考虑到UI/域交互不需要序列化,请保持简单并使用实际对象。

        3
  •  7
  •   bennidi    12 年前

    我认为DTO通常不是一种反模式。有很多人和系统在使用它们,您得到的好处是可以独立于域模型设计和模块化的分离视图层。尽管我同意在可能的情况下应该使用域对象,但在某些情况下,当您将视图层直接绑定到域模型时,可能会遇到问题。

    我在一个视图模型中取得了很好的经验,该模型只包装了域对象,并将大部分操作委托给它们。这将分离视图和域层,允许域对象的灵活组合,而且由于IDES支持委托模式,因此仍然不需要太多的工作来实现。

        4
  •  2
  •   Al1998    14 年前

    当要发送的域对象有问题时的方案:

    1. 您可能需要将聚合信息或其他类型的“计算字段”发送到UI层(例如flex/gwt),并且不希望弄乱域对象。
    2. 您可能会遇到对循环对象图进行序列化的需求(在您的示例中,如果学生具有列表关系),则某些协议对此存在问题。
    3. 处理框架序列化程序时出现Hibernate LazyinitializationException(flex/gwt序列化程序的Blazeds)

    我不确定这是一个明确的答案

        5
  •  2
  •   Aquarelle    11 年前

    在我看来,在每一层中使用域模型对象完全没有问题。你说你不需要所有的信息。当您在JSP中时,只使用您需要的数据。没有人强迫你把所有的财产都取走。你还说,你需要做与对象属性相关的计算,以获得GPA,学生等。你有3个选择:在你的域模型对象中创建合成属性,为你返回正确的数据,包装好整洁;在任意一个控制器或服务层,并通过适当的getter公开它们;或者在JSP中处理它们。您无论如何都需要检索/编译/争论数据,所以为什么要用DTO增加更多的复杂性。

    另外,对于每个DTO,您都在创建a.)一个您现在必须维护的额外类,b.)在某些类中的某个地方至少有一个额外的方法来构造和填充DTO(DAO、工厂方法等)。更多维护=6个月后开发人员不满意。

    所以,我反对DTO。我确实使用它们,但只在某些情况下使用,比如当我真的需要优化速度和/或内存使用时,并且为一个完整的域模型对象补水的成本太高了。Web服务是我喜欢使用DTO的一个很好的例子。

        6
  •  0
  •   Ilan Y    9 年前

    类或其内部方法的行为不应暴露于与它们的行为无关的层。传输数据,而不是行为。在域中使用域对象。Web不是受控域,UI开发人员不需要关心域行为,只关心数据。

    域必须被封装,并且不被与域健康无关的人修改。

    泄漏行为不是最好的习惯。

    如果是一个小项目,也要用正确的原则来建造。这样,我们总是记住为什么我们要做我们做的事,而不仅仅是怎么做。

        7
  •  -1
  •   kboom    11 年前

    我认为我们首先应该考虑的是引入新层的成本。以DTO为例-这样我们就需要一个映射。正如有人所说,翻译是邪恶的,应该尽可能避免。

    另一方面,我认为你通常不应该做的事情很少。那些说所有DTO都是邪恶的人是错误的——这总是取决于用例!他们真的合理吗?

    最后,我个人认为应该让域对象进入视图本身。想象一下Wicket集成是什么样子的。但以SpringMVC为例,域可能会留在应用层中…

        8
  •  -4
  •   dariopy    14 年前

    DTO现在被广泛认为是一种反模式,建议通常是“不惜一切代价避免它们”。

    像Hibernate这样的ORM框架的一个主要优点是,您可以在所有级别上使用域对象,并且不真正需要DTO。当然,需要注意的是,你必须花些时间来思考这些关系:什么时候使用懒惰的获取,什么时候使用渴望,等等。

    推荐文章