锁定老帖子 主题:贫血就贫血,咂地?
精华帖 (1) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-11-02
如果传统的依赖注射,那么让dao直接注射这些东西非常不好。dao本不该依赖SmtpService, WebServce, xxxService这些东西。
而如果dao不注射,让service层注射,也很笨拙。因为同样对一个domain object的注射可能需要出现在service层的若干不同的地方。 再加上依赖如果一多,正如xiecc所说,很容易出错。所以,能够让dao和service层都从这个繁琐的任务中解脱出来还是很好的。 在这点上,我和xiecc的观点还是吻合的。分歧在于:怎样把这个依赖管理以易于单元测试并且不引入对具体容器api依赖的方式独立出来。 |
|
返回顶楼 | |
发表时间:2005-11-02
确实在DAO和Service层注入都会带来不一致的问题。
所以唯一能够保证单点维护的方式就在对象返回的时候做。 ajoo最终提供的方式分别处理了find和new的方式,然后使用工厂来代替new。 这样确实使得问题简单了很多,但能否做到单点呢? 并且需要使用工厂...这个感觉也不太爽,毕竟工厂也要注入阿。 |
|
返回顶楼 | |
发表时间:2005-11-02
嗯嗯。
确实,无论injector还是工厂,都要注入。这也是我能想到的在保证单元测试能力不受影响,不依赖任何外界api的最简单的方法了。 其实,我始终感觉问题就出在这个rich domain身上。这个概念感觉先天就不对。要不叫它“充血”呢? |
|
返回顶楼 | |
发表时间:2005-11-02
ajoo 写道 嗯嗯。
确实,无论injector还是工厂,都要注入。这也是我能想到的在保证单元测试能力不受影响,不依赖任何外界api的最简单的方法了。 其实,我始终感觉问题就出在这个rich domain身上。这个概念感觉先天就不对。要不叫它“充血”呢? 不充血就成傀儡了。不妨说说你支持的Domain结构,俺已经预感到你的观点同我的不同,讨教讨教! |
|
返回顶楼 | |
发表时间:2005-11-02
ajoo 写道 嗯嗯。
确实,无论injector还是工厂,都要注入。这也是我能想到的在保证单元测试能力不受影响,不依赖任何外界api的最简单的方法了。 其实,我始终感觉问题就出在这个rich domain身上。这个概念感觉先天就不对。要不叫它“充血”呢? 似乎能做到单点维护的还是AOP?!可以在new return的时候做点文章。 |
|
返回顶楼 | |
发表时间:2005-11-02
partech 写道 他啥观点?你支持他啥观点?
以下都是支持的观点,就我的观点来说是:设计首先必须要能够直接明了的体现设计者的意图,也正是简单设计所追求的目标之一,复杂设计会掩盖设计者的本意并且带来模棱两可的假象,最终导致设计无法被正确理解。 ajoo 写道 更优雅的设计,在我看来,应该是Dao只返回纯数据的结构,比如BankAccountData,这个对象里除了getter/setter就没有业务逻辑。然后在service层面把BankAccountData转换为BankAccount。这样,就不存在一个半成品的状态,不存在假象。类型告诉我们什么可用,什么就必然可用。 我来给这个方法挑挑毛病: 1. 上面说过了。代码不容易理解。明明setSmtpService没有被调用,不知道有个aop会在预定地点冒出来得人抓破头皮也看不懂这程序怎么工作的。 2. 不容易unit test。这个代码能够工作,完全依赖于aop的存在。即使在单体测试,aop,以及容器也必须包含在内。 1. 首先,这个方法要足够简单。不引入额外的复杂性。 2. 其次,它应该对单体测试友好。 3. 最后,代码应该更易懂。 |
|
返回顶楼 | |
发表时间:2005-11-02
age0 写道 partech 写道 他啥观点?你支持他啥观点?
以下都是支持的观点,就我的观点来说是:设计首先必须要能够直接明了的体现设计者的意图,也正是简单设计所追求的目标之一,复杂设计会掩盖设计者的本意并且带来模棱两可的假象,最终导致设计无法被正确理解。 ajoo 写道 更优雅的设计,在我看来,应该是Dao只返回纯数据的结构,比如BankAccountData,这个对象里除了getter/setter就没有业务逻辑。然后在service层面把BankAccountData转换为BankAccount。这样,就不存在一个半成品的状态,不存在假象。类型告诉我们什么可用,什么就必然可用。 我来给这个方法挑挑毛病: 1. 上面说过了。代码不容易理解。明明setSmtpService没有被调用,不知道有个aop会在预定地点冒出来得人抓破头皮也看不懂这程序怎么工作的。 2. 不容易unit test。这个代码能够工作,完全依赖于aop的存在。即使在单体测试,aop,以及容器也必须包含在内。 1. 首先,这个方法要足够简单。不引入额外的复杂性。 2. 其次,它应该对单体测试友好。 3. 最后,代码应该更易懂。 关于如何优雅的设计Domain层,可以另外开帖i再讨论。 看不出这种只返回数据的方法,如何优雅。 最终的解决方案,并没有解决上面的毛病.setSmtpService的调用同样费解。 AOP完全可以认为是同java原有关键字同样的东西,不存在依赖问题。 |
|
返回顶楼 | |
发表时间:2005-11-02
partech 写道 ajoo 写道 嗯嗯。
确实,无论injector还是工厂,都要注入。这也是我能想到的在保证单元测试能力不受影响,不依赖任何外界api的最简单的方法了。 其实,我始终感觉问题就出在这个rich domain身上。这个概念感觉先天就不对。要不叫它“充血”呢? 似乎能做到单点维护的还是AOP?!可以在new return的时候做点文章。 不错。aop是对先天有毛病的东西打补丁的好手。不过,引入了aop,就引入了一个额外的依赖。象aspectj这种庞然大物,不到必要我是不喜欢用的。 单元测试将不得不依赖aop和aop代码使用的那个容器,这还叫单元测试吗? 代码也更难理解。(察看BankAccount的构造函数,明明没有设置依赖,但是它却神奇地工作了)。 何况,现在的那些aop解决方案,仍然是直接依赖容器的api,是service locator,这是不优雅的。 相比之下,即使是你不喜欢的injector方案,至少读代码的时候可以顺藤摸瓜:injector.inject(obj)可能作了什么,那些依赖很可能都被在这里设置了。这通过传统的线性思维就够了。而aop,则大概需要一定的发散思维才行。 其实,OO的多态就曾被人批评过有点象goto,因为调用一个多态函数的时候(injector.inject()就是了),我们无法简单地找到具体发生了什么。 但是,多态调用至少给了你线索,你知道这里肯定发生了什么。(injector.inject(obj)顾名思义,可能是注射了依赖)。 而aop,呵呵,在我看来用错了比goto还糟糕。goto只影响某个函数的局部,最差情况你就是看不懂一个函数的实现而已。 aop则在整个系统架构内部乱画辅助线,如果画的不好,影响的是整个系统的理解和维护。 说什么关键字云云,有点掩耳盗铃的感觉了。所有java的关键字都是你在某地写了什么,这个地方才会发生什么。我不调用某个函数或者间接调用这个函数的其它函数,这个函数就必然不会被调用。这种经典的“因果关系”已经成为我们普通人的常识了。 而aop颠覆这一切,在十万八千里外的蝴蝶扇了一下翅膀,就可能影响到紫禁城地下军事基地里面的核设施。而这种影响你盯着紫禁城看是没用地,必须幸运地有人告诉你哪里的蝴蝶扇了翅膀。大概只有聪明如波尔,海森堡等量子大拿才会对这种缺乏因果关系的事务间的普遍联系得心应手吧? spring的aop解决方案是利用了annotation,某种程度上帮助了可读性的问题。但是,这就让你的业务代码绑定在spring上了。不符合无侵入性原则。 |
|
返回顶楼 | |
发表时间:2005-11-02
ajoo 写道 partech 写道 ajoo 写道 嗯嗯。
确实,无论injector还是工厂,都要注入。这也是我能想到的在保证单元测试能力不受影响,不依赖任何外界api的最简单的方法了。 其实,我始终感觉问题就出在这个rich domain身上。这个概念感觉先天就不对。要不叫它“充血”呢? 似乎能做到单点维护的还是AOP?!可以在new return的时候做点文章。 不错。aop是对先天有毛病的东西打补丁的好手。不过,引入了aop,就引入了一个额外的依赖。象aspectj这种庞然大物,不到必要我是不喜欢用的。 单元测试将不得不依赖aop和aop代码使用的那个容器,这还叫单元测试吗? 代码也更难理解。(察看BankAccount的构造函数,明明没有设置依赖,但是它却神奇地工作了)。 何况,现在的那些aop解决方案,仍然是直接依赖容器的api,是service locator,这是不优雅的。 相比之下,即使是你不喜欢的injector方案,至少读代码的时候可以顺藤摸瓜:injector.inject(obj)可能作了什么,那些依赖很可能都被在这里设置了。这通过传统的线性思维就够了。而aop,则大概需要一定的发散思维才行。 其实,OO的多态就曾被人批评过有点象goto,因为调用一个多态函数的时候(injector.inject()就是了),我们无法简单地找到具体发生了什么。 但是,多态调用至少给了你线索,你知道这里肯定发生了什么。(injector.inject(obj)顾名思义,可能是注射了依赖)。 而aop,呵呵,在我看来用错了比goto还糟糕。goto只影响某个函数的局部,最差情况你就是看不懂一个函数的实现而已。 aop则在整个系统架构内部乱画辅助线,如果画的不好,影响的是整个系统的理解和维护。 说什么关键字云云,有点掩耳盗铃的感觉了。所有java的关键字都是你在某地写了什么,这个地方才会发生什么。我不调用某个函数或者间接调用这个函数的其它函数,这个函数就必然不会被调用。这种经典的“因果关系”已经成为我们普通人的常识了。 而aop颠覆这一切,在十万八千里外的蝴蝶扇了一下翅膀,就可能影响到紫禁城地下军事基地里面的核设施。而这种影响你盯着紫禁城看是没用地,必须幸运地有人告诉你哪里的蝴蝶扇了翅膀。大概只有聪明如波尔,海森堡等量子大拿才会对这种缺乏因果关系的事务间的普遍联系得心应手吧? spring的aop解决方案是利用了annotation,某种程度上帮助了可读性的问题。但是,这就让你的业务代码绑定在spring上了。不符合无侵入性原则。 是啊,当初OO出场的时候,同样有人说没有必要。C++能做到的C也能做到。 在你眼里,Aspect似乎是不可捉摸的东西,结构化的编程方法看OO也是摸不着头脑,AOP没有你说的那么毫无道理,恰恰相反,我认为他更加加强了封装,对关注点进行封装.对于AOP的指责,毫无意义,所有东西都有误用的可能,刀可以用来杀人,也可以用来切西瓜,你不能说刀是好还是不好。 我相信AspectJ也正处于C++的初始发展的阶段。有那么一天aspect会同class一样成为java的一等公民。java必将再次超越。 |
|
返回顶楼 | |
发表时间:2005-11-02
喊口号就不必了。aspect能走到哪里让我们拭目以待把。
确实,aop有它的关注点的理论。一个横切的关注点象transaction control, logging之类的,却是可能比较适合用aop。 但是,我们这里讨论的问题不是一个cross-cut的关注点。这个依赖注射和transaction, logging不同,它和我们要做的事情并非正交。后面的处理,如果没有这些依赖,就根本就无法继续,依赖注入在我们的流程里并不是一个分离的关注点,而是流程的一部分。这不是cross-cut。 更何况,即使我们搁置aspect的分歧,你也需要面对那个aop方案里仍然要直接依赖容器,仍然要service locator的弊病。 |
|
返回顶楼 | |