视图层中的DTO或域模型对象?
我知道这可能是一个古老的问题,但是更好的做法是什么? 在整个应用程序的所有层中使用一个领域模型对象,甚至直接将值绑定到JSP上(我使用的是JSF)。 或者将域模型对象转换为DAO或服务层中的DTO,并将轻量级DTO发送到表示层。
我被告知,使用DTO是没有意义的,因为对数据库的更改将导致所有DTO的更改,而在任何地方使用模型对象只需要更改受影响的模型对象。 但是,DTO的易用性和轻便性似乎超过了这一点。
我应该注意到,我的应用程序使用Hibernate模型对象,并使用自己的自定义创build的模型对象(意思是不绑定到任何数据库会话,总是分离)。 上述任何一种情况对于严格的模型对象模式都更有利? 对于Lazy Initialization Exceptions这样的事情来说,使用Hibernate是一个巨大的PITA。
我正在编辑这个问题,希望进一步讨论(不知道我是否正确):
我对模型对象的问题是它们根本不灵活。 下面的评论说应该devise应用程序,以便模型对象可以在所有图层中使用。 为什么? 如果一个用户想要一个荒谬的function,我应该告诉他们,“那么将无法与模型对象?
简单而简单,有时候模型对象不能工作。 你可能有:
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的总平均数? 这似乎更像是花了更多的努力,而不是简单地创build一个“stringlastName”,“int numStudents”,和“double combinedGpa;
这可能听起来像我的思想已经弥补了这些,但我还没有在一个应用程序中的模型对象可以在任何情况下完全使用干净。 普通的真实世界的应用与普通的用户需求不一样。
这真的取决于你的应用程序的复杂性。 将域对象混合到视图层有两个可能的含义:
- 你会试图修改你的域对象,以适应视图层中你需要的东西
- 您的视图图层将包含由您的域对象提供的内容与您的视图真正需要的不匹配所导致的额外复杂性。 你可能无法绕过这个复杂性,但它可能不属于View层。
如果你的域对象很简单并且你的视图很less,跳过DTO可能是最简单的事情。
另一方面,如果你的领域模型有可能演变并变得复杂,并且如果你的观点可能是多种多样的,那么查看特定对象可能是一个好主意。 在MVC世界里,使用ViewModels是很常见的,对我来说很有意义。
另一个投票域对象。 就领域驱动devise而言,领域模型是国王,应尽可能使用领域模型。 应用程序的devise应以大多数图层(酒吧基础设施层)可以使用域对象的方式进行devise。
我认为只有在对象需要序列化的情况下,DTO才是有用的。 如果没有通过电汇或不兼容的架构转移,我不会使用它们。 DTO模式对保持序列化不在域对象中很有用。 考虑到UI /域的交互不需要序列化,保持简单并使用实际的对象。
我认为有DTO不是一般的反模式。 有很多人和使用它们的系统,你得到的好处是可以独立于领域模型devise和模块化的解耦视图层。 尽pipe我同意在可能的情况下应该使用域对象,但在将视图层直接绑定到域模型时,您可能会遇到问题。
我用一个视图模型取得了很好的经验,这个视图模型只包含域对象,并将大部分操作委托给它们。这样解耦视图和域图层,允许灵活地组合域对象,并且由于IDE支持,委派模式。
当域对象有问题时发送的情况:
- 你可能需要汇总的信息或其他types的“计算的字段”发送到UI层(例如Flex / GWT),而不想混乱域对象
- 你可能会遇到序列化循环对象图的需求(在你的例子中,如果Student有List关系),有些协议有问题
- 处理框架序列化程序(flex / GWT序列化程序的blazeDS)时发生Hibernate LazyInitializationException
在这些情况下,我不确定这是一个明确的答案
在我看来,在每个图层中使用域模型对象都没有问题。 你说你不需要所有的信息。 当你在JSP中时,只使用你需要的数据。 没有人强迫你拿取每一个财产。 你还说你需要进行与对象属性相关的计算,以获得GPA,学生人数等。你有3个select:在你的领域模型对象中创build合成属性,为你返回正确的数据,包装好整洁 在控制器或服务层中进行计算,并通过适当的获得者来公开它们; 或者在你的JSP里面处理。 您需要检索/编译/缠绕数据ANYWAY,那么为什么要增加一个DTO的复杂性。
另外,对于每个DTO,您正在创build一个。)一个额外的类,您现在必须维护,以及b。)在某个类的某个地方的某处,使用至less1个额外的方法来构造和填充DTO(DAO,工厂方法等) 。 更多的维护=开发6个月后不开心。
所以,我有反对DTO的论点。 我使用它们,但只在某些情况下,例如当我真的需要优化速度和/或内存使用情况时,保护完整的域模型对象的代价太大了。 当我更喜欢使用DTO时,Web服务就是一个很好的例子。
一个类或其内部方法的行为不应该暴露于不关心其行为的层。 传输数据,而不是行为。 使用域内的域对象。 networking不是一个受控的领域,UI开发人员不需要关心域行为,只需要关心数据。
该域名必须被封装,并且不得被不关心该域名健康的人修改。
泄漏行为不是最好的习惯。
如果它是一个小项目,也build立了正确的principes。 那样我们总是记住我们为什么要做我们做的事情,而不是如何做。
我想我们首先应该考虑的是引入新层的成本。 以DTO为例 – 这样做,我们需要一个映射。 正如有人所说,翻译是邪恶的,应尽可能避免。
另一方面,我认为你通常不应该做的事情很less。 那些说所有的DTO是邪恶的都是错误的 – 它总是取决于用例! 他们真的有道理吗?
最后,我个人认为域对象应该放到视图本身。 想象一下,如何集成小门。 但以Spring MVC为例 – 域可能会留在应用程序层可能…
目前,DTO被广泛认为是反模式,build议通常是“不惜一切代价避免”。
像Hibernate这样的ORM框架的一个主要优点是你可以在各个层次上使用域对象,而且不需要DTO。 当然,要注意的一点是,你必须花时间去思考这些关系:什么时候使用懒惰提取,何时使用渴望等等。