避免贫血领域模型

3
我有一个数据库中的列,看起来像“Country/Province/City”,例如“Canada/Ontario/Toronto”。我需要将它们拆分并映射到3个单独的Java Bean属性中。
我想知道最好在哪里做这件事?
(1)DAO在检索行时 (2)Domain(Bean)在调用setter和getter时 (3)使用SQL函数解析查询中的行 (4)使用ResultSetExtractor 我倾向于选择#2或#4,因为“贫血领域”反模式表明Bean是适当的地方。

数据访问对象。这是商业软件世界中使用的标准模式。 - Marko Topolnik
4个回答

2

我不确定我是否同意你的观点;你可以说领域实体不需要受到数据表示的影响。
如果你的数据库布局不同,你会考虑使用具有setter和getter方法的bean吗?
如果你的答案是“不”,那么你可能不想选择这个选项。

就我个人而言,我认为如果你有一个数据访问层,那么它的工作之一就是将数据表示转换为领域表示。


贫血领域作为反模式的资格并没有达到现实的要求。在商业软件中,实际上需要完全分离功能和数据模型。面向对象编程对于业务逻辑来说并没有太多的帮助。事实上,它通常会通过要求将每个函数分派到一个对象上来导致巨大且难以维护的对象图而拖慢它。甚至没有人尝试构建它们,而是将图形构建委托给自动装配IoC框架。 - Marko Topolnik
你又一次把你的观点当作事实陈述。 - J. Ed
+1 DAO 是进行此翻译的正确场所。领域对象应该反映真实的业务模型,而不是持久化模型(在许多情况下由于遗留原因而偏离)。 - casablanca

1

个人认为,最好的地方是数据库。我会在表格中将此列分成3列,并按列存储一个信息。

如果由于遗留原因真的不可行,我会直接在域对象中实现这个功能。这是可以直接封装在域对象中的行为,不会对其他实体产生任何影响。


我想避免使用数据库的原因是我担心分隔路径项可能会更改以包含更多或更少的节点,而我希望具有适应性。即第二个节点在某些情况下可能不总是省份,因此我可能需要应用逻辑来确定它。越看这个问题,我越喜欢使用ResultSetExtractor(Spring JDBC)。它不完全是Bean,也不完全是DAO。它处于两者之间。 - EdgeCase
路径越复杂,我认为你就越需要一个规范化的数据模型。否则,你最终会将XML、JSON或序列化对象存储在单个列中,这样你就无法再查询你的数据了。一列只存储一个信息。 - JB Nizet
如果重新设计数据库的选项仍然对您开放,那么您应该绝对优先考虑这一点。拥有良好结构化模型的优势是无可比拟的。我认为我们只有在失败后才应讨论其他选项。 - Marko Topolnik
顺便问一下,为什么ResultSetExtractor不在你的DAO里面?在我参与的项目中,这通常都是这样的。 - Marko Topolnik
@MarkoTopolnik - 我正在使用以下示例作为设计基础。 http://forum.springsource.org/showthread.php?51731-JDBCTemplate-or-SimpleJDBCTemplate-example-using-ResultSetExtractor - EdgeCase
我明白了。我认为那段代码有点脱离上下文。我们通常会将ResultSetExtractor实现作为DAO类的内部类,甚至是方法内的匿名类——这取决于它将被重用的程度。把它放在自己的文件中并不是惯例。但即使它在单独的文件中,它仍然算作DAO层的一部分。 - Marko Topolnik

0
如果这是一个JPA实体,那么我会将私有字符串直接映射到数据库列,然后创建公共的getter方法来封装访问它的方式。这样,您域模型的使用者就可以从连接字符串的内部/数据库表示中隔离开来。或者,您可以在@PostLoad回调中进行翻译。(在持久化时进行反向翻译可以在@PrePersist回调中完成。)

0

你的第一点和第四点实际上不是同一个解决方案吗?我猜你会在DAO代码中使用ResultSetExtractor。使用SQL函数并不是一个坏主意,因为它可以从其他技术中重复使用,但是有维护问题。

我不建议延迟解析直到获取时间,因为这对性能来说不好,并且在处理这些字段的其他任务时可能会让你的生活变得复杂。如果你的bean已经有了这三个字段,那么就更清晰了。


是的,如果我的DAO和Extractor在同一个类中,但我已经将它们分开了 - 不管对错。请参见我对您上面问题的回答。 - EdgeCase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接