2010-04-21 61 views
48

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

我被告知使用DTO是没有意义的,因为对数据库的更改将导致所有DTO的更改,而到处使用模型对象只需要更改受影响的模型对象。但是,DTO的易用性和轻便性似乎超过了这一点。

我应该注意到我的应用程序使用Hibernate模型对象并使用自己的自定义创建的模型对象(意思是不绑定到任何数据库会话,总是分离)。上述任何一种情况对于严格的模型对象模式都更有利?对于Lazy Initialization Exceptions这样的事情来说,使用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总和。在这种情况下你会做什么?检索完整的教师信息和学生关系,然后你的代码在学生名单上计数,然后计算所有gpas的总平均数?这似乎比通过'String lastName','int numStudents'和'double combinedGpa'创建DTO更省力。

这可能听起来像我的想法已经弥补了这些,但我还没有在模型对象可以完全在每个实例中完全使用的应用程序中工作。普通的真实世界的应用程序不符合普通的用户需求,但并不是那样。

回答

30

一个明确的答案这真的取决于你的应用程序的复杂性。混合域对象到视图层有两种可能的含义:

  1. 你会被诱惑去修改你的域对象,以适应您的视图层需要
  2. 您的视图层将包含额外造成了复杂的事情您的域对象提供的内容与您的视图真正需要的内容不匹配。您可能无法绕过这种复杂性,但它可能不属于View层。

如果您的域对象很简单并且您的视图很少,那么跳过DTO可能是最简单的事情。另一方面,如果你的领域模型有可能演化并变得复杂,并且如果你的观点可能是多种多样的,那么查看特定对象可能是一个好主意。在MVC世界中,使用ViewModels是很常见的,对我来说很有意义。

-4

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

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

+0

是的,我明白了。它看起来好像有时会增加不必要的复杂性。如果我有一个表示老师的对象,并且有时候我只需要头信息(姓名,地址),我必须发送一个半人口填充的域对象到前端。它只是一种误导,似乎不正确的我。 – sma 2010-04-21 13:43:27

+4

@ smayers81 - 你为什么只在中途填充你的域对象?这听起来像是一种不必要的优化(当然,如果你已经进行了配置或者发现了一个问题,那当然不会)这听起来像你的问题的根源 - 对待你的域对象,如DTOs。为什么不把你的完全水合的域对象推到前端?如果你发现你有一个性能问题,那么你有一个DTO的例子(或者完全绕过自定义对象,并直接处理你的框架提供的任何记录集抽象)。 – 2010-04-28 16:41:54

+0

因为我总是觉得,如果没有真正需要,通过网络发送所有数据。我认为这是Hibernate的懒惰理念背后的全部动力(我可能在那里错了) – sma 2010-04-30 00:32:29

7

对域对象的另一投票。就领域驱动设计而言,领域模型是国王,应尽可能使用领域模型。应用程序的设计应该以大多数图层(酒吧基础设施层)可以使用域对象的方式进行。

我认为DTOs只在对象需要序列化时才有用。如果没有通过线路传输或不兼容的架构,我不会使用它们。 DTO模式对保持序列化不在域对象中很有用。考虑到UI /域的交互不需要序列化,保持简单并使用实际的对象。

+3

我认为会话需要序列化集群环境中的状态管理?即使我们现在拥有的模型对象(休眠模型和定制的,分离的模型对象)都是可序列化的。 – sma 2010-04-21 13:40:32

+2

我不认为他指的是你正在谈论的序列化(a-la Serializable)。我认为他的意思是序列化XML,JSON,AMF(Flex),CSV等等。 – Aquarelle 2013-04-10 06:08:29

2

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

  1. 可能需要聚集的信息或其它类型的“计算字段”发送到UI层(在示例的Flex/GWT)的和不希望乱域对象
  2. 你可能会遇到需要序列化循环对象图(在你的榜样,如果学生有列表关系),与框架序列化处理(BlazeDS的用于当一些协议具有与
  3. Hibernate的LazyInitializationException中的问题flex/GWT串行器)

我不知道它在那些cirumcstances

7

我认为DTO并不是一般的反模式。有很多人和使用它们的系统,您获得的好处是可以独立于域模型进行设计和模块化的解耦视图层。虽然我同意你应该尽可能使用域对象,但是当你将视图层直接绑定到域模型时,有些情况下你可能会遇到问题。

我对视图模型做了很好的体验,它只包含域对象并将大部分操作委托给它们。这样可以解耦视图和域图层,允许灵活组合域对象,并且不需要太多工作因为IDE支持委托模式。

1

在我看来,在每个图层中使用域模型对象都没有问题。你说你不需要所有的信息。当你在JSP中时,只使用你需要的数据。没有人强迫你拿取每一个财产。你还说你需要进行与对象属性相关的计算才能获得GPA,学生数量等等。你有3个选择:在你的领域模型对象中创建综合属性,为你返回正确的数据,包装好整齐;在控制器或服务层中执行计算,并通过适当的获得者来公开它们;或者在你的JSP中处理它。您需要检索/编译/缠绕数据ANYWAY,所以为什么要增加DTO的复杂性。 (DTO),工厂方法(DAO),工厂方法(DAO)等)。 6个月后,更多的维护=开心的开发者。

所以,我的论点反对DTOs。我确实使用它们,但只在某些情况下,比如当我真的需要针对速度和/或内存使用进行优化时,保护完整域模型对象的成本太高。当我更喜欢使用DTO时,Web服务就是一个很好的例子。

-1

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

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

最后,我个人认为域对象应该放到视图本身。想象一下,Wicket集成是什么样子。但以Spring MVC为例 - 域可能会留在应用程序层中,可能...

0

类或其内部方法的行为不应暴露给与其行为无关的层。传输数据,而不是行为。使用域内的域对象。网络不是一个受控制的域,UI开发人员不需要关心域行为,只需要关注数据。

该域名必须被封装,并且不得被不关心该域名健康的人修改。

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

如果是一个小项目,也可以使用正确的principes构建它。这样我们总是记住我们为什么要做我们所做的事情,而不是如何做。