锁定老帖子 主题:为什么我的程序传递DTO
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-03-18
partech 写道 firebody 写道 问题是 DomainObject不允许跑出Domain层,就一定需要使用DTO吗?
正如我前面所说的,我们也可以让View层依赖于平面的数据,比如XML等等。 让中间层作这么一个架构的设计。 而且从你提供的代码来看,仍然脱离不了重复性的代码而逻辑重复的各种Assembler 。 这种代码我认为是不大“舒服“得。 而且,为了阐明我的观点,我想引用一下你的标题: 再明确分层的前提下,一定需要DTO吗?我的答案是尽量避免使用DTO。 即使这样的结果需要一个精心设计的中间层作数据组装,我仍然觉得很有必要。 而且Controller和哪个中间层的设计完全可以参照webwork的思路。这样的一个设计如果能够消除DTO的出现,我想我会优先考虑的。 "尽量避免DTO"?看起来DTO就像“瘟疫”一样需要躲避。 如果你认为平面格式的XML就不是DTO,而是“需要一个精心设计的中间层作数据组装”,那么,我们的观点在我来看,并没有什么不同。DTO就一定要是java的某个类?你的平面XML数据,也还是需要Transfer吧。我认为它也是DTO的其中一种表现形式。 俺的代码,就那么几个简单的转换方法,俺还真看不出重复在哪里呢。 并且用“尽量避免DTO”来作为开发的指导思想,意义并不大。这往往意味着概念不清楚。 下面该我发飚了,前面问的问题,一直没支持透传PO的人出来澄清。 “ 表示层直接耦合业务层,使得夹在它们之间的Service层,还有什么意义?表示层接受PO,是否意味着,表示层可以修改PO?PO可以在表示层修改,那么Domain层还有多少意义?我是否可以把PO在表示层完全修改好,然后传递回后台,后台只负责简单的持久化。业务对象(BO)还有必须存在的理由吗? ” DTO不是瘟疫,我有时候也会选择它,因为我总是喜欢作权衡的选择,如果它暂且让我舒服,拿我就会选择它。 你说的不错:你的平面XML数据,也还是需要Transfer吧。我认为它也是DTO的其中一种表现形式。 其实我想说就基本使这个观点。 另外我也想说,让界面依赖于平面数据(XML)可以让分层进行得更彻底,而且也免去DTO带来的缺点 。只不过它对于中间数据转换层的设计要求要搞一些,带来的好处就是整体架构的含金两更高,因为它可以很清晰的分层,很好的省却后台逻辑代码的工作量,设计思路也很简介和清晰。 至于说吧PO透传到view的说法,我觉得这个说法应该起源于webwork和struts的争论,我认为这个说法有失偏颇, 这句话让我的感觉就是一个技术推销者跟不懂技术的人说的营销华语。 我觉得更准确的说法应该是用一个数据抽取层直接从PO中获取所需要的数据给视图,反之,就是通过数据转换层直接将view回来的数据设置到目标PO中。 如果硬是要“透传“这个词的话,那么我认为: 透传应该理解为中间转换层的作用而且省却DTO的类的设计和组合。 |
|
返回顶楼 | |
发表时间:2006-03-18
引用 我觉得更准确的说法应该是用一个数据抽取层直接从PO中获取所需要的数据给视图,反之,就是通过数据转换层直接将view回来的数据设置到目标PO中
赞同 连接前面讨论的三个阶段就叫控制层吧(听说人家这么叫的),.所以,输入数据的解析权,返回数据的格式,皆由该层来决定. 假如还有进一步抽取的必要,可以在加入一个数据抽取层,同样的对应输入数据的抽取也可结合到该抽取层(又是一个控制层!...).总之爱在前面套多少个输入数据,输出数据转换的层都可以.但不管这样的层有多少个,总有一层必须理解业务实体,以做转换. 甚至也可以把显示的页面看成一个控制层,只是到了这层,它的输出数据不在是有结构的,而是满足人的视觉需要的一个画面.生成这样的画面的工作也必须理解上一个控制层返回的数据格式. 隐藏业务实体的内部细节有时候或者是有必要的,但这种隐藏必须是建立在返回数据能完整正确的表达业务实体包含的意义上,所以这个转换工作必须是在理解了业务实体的内部细节上.并且这种隐藏不总是必须的. 所以由于必须理解业务实体的内部细节,转换工作不可能是通用的(也不是必须的), 所以支持控制层只有一个(假如需要转换成xml这样的格式,那再加一个吧!...),如何隐藏业务实体的内部细节,由聪明的开发者来决定!... |
|
返回顶楼 | |
发表时间:2006-03-19
引用 我觉得更准确的说法应该是用一个数据抽取层直接从PO中获取所需要的数据给视图,反之,就是通过数据转换层直接将view回来的数据设置到目标PO中。
两位都赞同上面的观点。但,这不还是DTO模式吗? 数据抽取层抽取数据的结果难道不是DTO吗?View回来的数据不一样也是DTO吗?数据抽取层的职责难道不是Assembler的职责? 还有一个问题,要问问两位,你们这个数据抽取层同Service层是啥关系? |
|
返回顶楼 | |
发表时间:2006-03-19
partech 写道 引用 我觉得更准确的说法应该是用一个数据抽取层直接从PO中获取所需要的数据给视图,反之,就是通过数据转换层直接将view回来的数据设置到目标PO中。
两位都赞同上面的观点。但,这不还是DTO模式吗? 数据抽取层抽取数据的结果难道不是DTO吗?View回来的数据不一样也是DTO吗?数据抽取层的职责难道不是Assembler的职责? 还有一个问题,要问问两位,你们这个数据抽取层同Service层是啥关系? 不好意思,可能我的观点让你感到有些模糊,因为这些观点的提取来源于Webwork与ognl/template view的结合。 如果吧DTO归结为一个个装载PO数据的载体的话,那么我所提到的这个数据抽取层并不是这样的DTO的概念,我用几个具体的例子说明这种模式的概念吧: 对于client的请求:它的输入是平面的数据,输出是一个个领域模型的PO实体,如果是更新动作的话,它还可能包括调用对应Action对象或者PO上的setter方法。 对于响应: 它的输入是Action对象/PO对象,输出是平面数据。 站在Service的视角来看,Service层只看到PO对象。 站在Action对象的视角来看,它只看到Service对象/PO对象。 |
|
返回顶楼 | |
发表时间:2006-03-19
firebody 写道 不好意思,可能我的观点让你感到有些模糊,因为这些观点的提取来源于Webwork与ognl/template view的结合。
如果吧DTO归结为一个个装载PO数据的载体的话,那么我所提到的这个数据抽取层并不是这样的DTO的概念,我用几个具体的例子说明这种模式的概念吧: 对于client的请求:它的输入是平面的数据,输出是一个个领域模型的PO实体,如果是更新动作的话,它还可能包括调用对应Action对象或者PO上的setter方法。 对于响应: 它的输入是Action对象/PO对象,输出是平面数据。 站在Service的视角来看,Service层只看到PO对象。 站在Action对象的视角来看,它只看到Service对象/PO对象。 不知道画的图有没有表达你们的意思?上图 画了画图,才发现,俺的意思准确的来说,是DomainObject不允许跑出Service层才对。下图 |
|
返回顶楼 | |
发表时间:2006-03-19
partech 写道 firebody 写道 不好意思,可能我的观点让你感到有些模糊,因为这些观点的提取来源于Webwork与ognl/template view的结合。
如果吧DTO归结为一个个装载PO数据的载体的话,那么我所提到的这个数据抽取层并不是这样的DTO的概念,我用几个具体的例子说明这种模式的概念吧: 对于client的请求:它的输入是平面的数据,输出是一个个领域模型的PO实体,如果是更新动作的话,它还可能包括调用对应Action对象或者PO上的setter方法。 对于响应: 它的输入是Action对象/PO对象,输出是平面数据。 站在Service的视角来看,Service层只看到PO对象。 站在Action对象的视角来看,它只看到Service对象/PO对象。 不知道画的图有没有表达你们的意思?上图 画了画图,才发现,俺的意思准确的来说,是DomainObject不允许跑出Service层才对。下图 差不多是这样的意思了,不过数据抽取层并不依赖于Service,而是Action依赖于Service .因为数据抽取层只作数据转换的动作。 领域模型是Server端逻辑的根基,Action依赖于PO我不觉得有任何的问题。 另外值得说明一点的是: 利用OGNL ,(或者CGLIB/Reflection), 数据抽取层也没有依赖于PO的。它可以精巧的设计成一个通用的框架。 |
|
返回顶楼 | |
发表时间:2006-03-19
firebody 写道 差不多是这样的意思了,不过数据抽取层并不依赖于Service,而是Action依赖于Service .因为数据抽取层只作数据转换的动作。
领域模型是Server端逻辑的根基,Action依赖于PO我不觉得有任何的问题。 另外值得说明一点的是: 利用OGNL ,(或者CGLIB/Reflection), 数据抽取层也没有依赖于PO的。它可以精巧的设计成一个通用的框架。 好了,按照你的要求改好了。这下好了吗? 不管你的数据抽取层使用什么方法,来构建PO,我想具体的配置总是需要的, 依赖就在这些配置中,还是属于抽取的范畴,不是吗? 继续我的问题: 1.Action依赖于PO,同数据抽取对象不同,它具体都对PO做了些什么操作呢? 2.如果现在表示层是RichClient,或者是第三方的独立程序,能告诉我,你将在哪里把它们劈开吗? |
|
返回顶楼 | |
发表时间:2006-03-19
假设数据抽取只是偶尔的,假设domain object是充血的,那么独立的数据抽取和叫service的两个控制层不需要.
那么只有一个控制层(叫action,叫service都一样). 结构如下. action->domain object view->domain object(如果domain object包括一些业务方法,那么可以clone一个domain object,只包括数据,或者返回一个unmodify的domain object,或者domain object再分为数据模型接口和业务方法接口两部分,只让view了解数据模型接口这部分) view->一些隐藏业务实体细节的object. |
|
返回顶楼 | |
发表时间:2006-03-19
partech 写道 firebody 写道 差不多是这样的意思了,不过数据抽取层并不依赖于Service,而是Action依赖于Service .因为数据抽取层只作数据转换的动作。
领域模型是Server端逻辑的根基,Action依赖于PO我不觉得有任何的问题。 另外值得说明一点的是: 利用OGNL ,(或者CGLIB/Reflection), 数据抽取层也没有依赖于PO的。它可以精巧的设计成一个通用的框架。 好了,按照你的要求改好了。这下好了吗? 不管你的数据抽取层使用什么方法,来构建PO,我想具体的配置总是需要的, 依赖就在这些配置中,还是属于抽取的范畴,不是吗? 继续我的问题: 1.Action依赖于PO,同数据抽取对象不同,它具体都对PO做了些什么操作呢? 2.如果现在表示层是RichClient,或者是第三方的独立程序,能告诉我,你将在哪里把它们劈开吗? 1) 通过Action,我们可以暴露PO给数据转换层,数据转换层其实主要跟Action打交道,从它的视角来看,它只依赖于Action。 而我们要把PO数据输入给数据转换层只能通过Action来做,一个请求显示ID:1的Person这么一个过程: 数据转换层--- input(ID:1) -->Action<----(抽取ID==1的Person)----数据转换层。 伪代码如下: 1) action.setPersonId(1) 2) action.getPerson() { return service.findPersonById(id) ; } 至于说Action依赖于PO,这是很自然的一个依赖啊,它需要调用Service的方法,需要传递对应的PO实体啊。 构造和调用Action上相应的方法完成PO实体的查找/更新/以及相应 的动作,则是 数据转换层和Controller的职责了。 Action所需要做的就是提供相应的hooker 方法。 2) 我不是很理解这个问题 ,如果是平面数据的传递,Client端 和Server段的逻辑和动作可以隔离测试的阿,因为从CLient的视角来看,它只看关注输入的平面数据和输出相应的平面数据而已。 至于你说的配置问题,如果它的逻辑清除,作为架构的一个组成部分,我不觉的它有什么问题。 |
|
返回顶楼 | |
发表时间:2006-03-20
partech 写道 yimlin 写道 不过写太多的assembler代码也很郁闷的,希望有一种类似hibernate的东西来处理,尝试中。
赫赫,你这个建议怕是要吓跑很多人。 一个hibernate就够花时间学习了,难道还需要第二个? 就我看来,assembler的转换工作比起hibernate的OR来说,百分之一吧。 没有metadata,cache,indentitymap,hql。转化代码确实很简单。 呵呵,是比较简单,可是不可否认它很繁琐。我是很同意firebody的平面数据的方式来做。 我的目的是:从表现层到控制层,和从控制层到表现层的数据转换工作一致。 现在有这么多种控制层到表现层技术,包括velocity,freemarker,fastm等,以及表现层到控制层技术,如strusts的actionForm(比较不爽)和spring的mvc的binder技术(好一点,提供formBackingObject实现就可)。 不过总觉的既然hibernate可以在系统的一个边界上提供一致的数据转换工作,为什么不能在另一个边界上提供类似的行为! |
|
返回顶楼 | |