锁定老帖子 主题:复杂还是不复杂?
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-02-04
一个MyService类里面,有一个MyResponse runService()函数。这个runService函数会调用一个web service来得到MyResponse对象。这个MyResponse对象在runService()函数中被缓存,然后返回。 现在的目标是,在runService返回以前,先把MyResponse clone一下,然后如果MyResponse.getCensus().getSalary()返回的带有几毛几分的零钱,就把这个salary truncate成整数。 需求不难,一个直观的解决方案是: java 代码
CloneUtil是现成的。只要写一个SalaryTruncationUtil类就算完工了。 可是问题出现在,这个系统存在着一个ResponseManipulator接口(在另外一个package里面)。 ResponseManipulator的接口如下: java 代码
从签名上,可以看出一个ResponseManipulator负责操作一个MyResponse,然后返回一个新的(或者原来的MyResponse)对象。 同时,另外还现存一个ChainResponseManipulator类,它负责把若干个ResponseManipulator对象串起来: java 代码
于是,我的pair决定这样写: java 代码
当然,还要实现一个TruncateSalaryManipulator。实现起来非常简单,就不写了。 我反对这个设计。虽然两者在代码量上不相伯仲,但是我认为这个设计无谓地增加复杂性,有一种绕着弯子解决简单问题的感觉。一个简单的顺序操作非要用一个特殊的接口和一个特殊的ChainResponseManipulator来实现。 一般来说,用接口是为了得到多态,降低耦合。可是在pair的代码里,该有的依赖一个没少,这个接口就显得意义寥寥。 而且这样做其实增大了MyService的依赖,因为凭空多了对ResponseManipulator和ChainResponseManipulator的依赖。 另外,ChainResponseManipulator对debug也不是非常友好,你单步运行每一个manipulator只能在ChainResponseManipulator的代码中,而不是MyService的代码中。 pair的观点有三: 1。看不出我的方案比用Manipulator有什么简单性的优势。 2。ChainResponseManipulator这一套设施已经存在,又不需要从头写。而且别人都是这么干的。 3。debug可以在每个不同的Manipulator类里面设置断点。 总而言之,没有达成一致意见。因为是pair主导键盘,所以最终pair的方案获胜。 今天在想怎么说服pair的时候,想了这么一个例子: 假设已经有一个StringAppender类: java 代码
是不是已经有了的设施,为了保持一致性就必须要使用呢?即使有更简便的方法? 关于这个问题,你怎么看? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-02-04
我觉得两种做法是半斤八两。如果系统没有现成的Manipulator的,那当然用简单的。现在已经有了Manipulator,少用一次多用一次并不改变依赖性。无可无不可的事,当然就是谁主导就听谁的,否则一起共事会很难过的。
|
|
返回顶楼 | |
发表时间:2007-02-04
我同意 pojo 这一观点
不过我觉得从代码的维护角度讲, 简单的那种很容易让人理解. 而采用现成的 Manipulator , 写出来的代码, 让人看起来有点点 "玄". |
|
返回顶楼 | |
发表时间:2007-02-04
已经有轮子了,嫌老的轮子磨损太严重!那么可以重新造一只!
成本论,如果在赛场上,你领先其他人很多圈,那么有时间造一只全新的,也无可厚非! 但是如果你没时间,还是跑完全程再说吧! 复杂程度来说,前者肯定复杂! |
|
返回顶楼 | |
发表时间:2007-02-04
如果从编码风格一致性来讲,既然已经有现成的基础设施,那使用既有代码无可厚非,而且从维护者角度考虑,一致的写法更为友好。
|
|
返回顶楼 | |
发表时间:2007-02-04
这种情况很经常遇到,一般是根据项目的规模和时间来决定
刚开始编程的时候,我是吸收的J道那里的banq的思路。 就是在自己的业务层中,只调用更下层的代码,而不是复用已经有了的同层代码。 如果业务简单,就自己写一遍。 如果必须引用已经有了的同层代码,因为度量和减少代码冗余以便维护的缘故,我倾向于用Adapter或者Mediater模式,用接口封装和重构同层的代码。而不是直接引用其它人写的包的东西。 引用之前,把别人的类给包装下先。因为不知道其它人在编写代码的时候,会不会修改已经编写好的类,如果你依赖了他,然而在不知情的情况下,其它人又对你依赖的类进行了修改,就会非常麻烦。所以用结构型设计模式进行下解耦,是面向对象编程的一个基本功。 如果是原来,我倾向你的解决方案。因为那个符合“好莱坞原则”还有Banq的无为的道的思想。那个思想对我影响比较深刻。而且你的代码是高聚合,低耦合的。毕竟复用和耦合,在某种情况下是存在矛盾的。 不过现在我觉得OO这套有点过时了,有时候OO到成了代码复用的障碍,那个第二个应该用的是IOC的思路在里面,不过问题是由于JAVA接口方面的限制,反而导致耦合的加强,这个应该是JAVA语法的原因,不是编程的原因,毕竟依赖的只是接口而已。 |
|
返回顶楼 | |
发表时间:2007-02-04
引用 那么在面对把两个对象连接成一个对象的时候,我们是:obj1.toString()+obj2.toString()呢?还是:new StringAppender(new Object[]{obj1, obj2}).toString()呢
感觉还是用StringAppender好些。 并非是因为有了StringAppender才想到要用这个,而是因为有了 obj1.toString()+obj2.toString()+obj3.toString()+...+objn.toString() 这样的表达式,才会想到要写一个StringAppender类的。 |
|
返回顶楼 | |
发表时间:2007-02-05
光从这里的代码来看,看不出两个方案的优劣来,不过你的pair的方案确实存在“误用”的嫌疑: 代码依赖于ChainResponseManipulator这个类。
但是,如果考虑别的Service也需要你写的 功能的话,别人可能会这样调用:
这样的话,可能会发挥一点 ResponseManipulator 的作用。 不过光从代码来看,可能也不会比你的方法少到哪里去。 一种比较实在的写法可以这样:
这样的写法一样可以达到代码复用的好处。 上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 两者,放在不同的环境里面,或许有各自的用处把。 |
|
返回顶楼 | |
发表时间:2007-02-05
firebody 写道: 光从这里的代码来看,看不出两个方案的优劣来,不过你的pair的方案确实存在“误用”的嫌疑: 代码依赖于ChainResponseManipulator这个类。
但是,如果考虑别的Service也需要你写的 功能的话,别人可能会这样调用:
这样的话,可能会发挥一点 ResponseManipulator 的作用。 不过光从代码来看,可能也不会比你的方法少到哪里去。 一种比较实在的写法可以这样:
这样的写法一样可以达到代码复用的好处。 上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 两者,放在不同的环境里面,或许有各自的用处把。
第一种也可以有灵活度, 如: ManupuateSupport.add(MyResponse...); ManupuateSupport.addAndManipulate(MyResponse...); 还可以有batch或readConfig等等 |
|
返回顶楼 | |
发表时间:2007-02-07
灵活度看怎么说了。
就在我们要完成这个功能的时候,我忽然想到:如果不需要truncate,那么根本就没必要clone。 跟同事一说,他愣了半天。因为要实现这个功能ChainManipulator就不好使了。最后只好说,先这么放着,如果真有效率问题再说。 其实这个功能如果不用Manipulator,非常简单。不过就是: if(needsTruncation(response)){ response = CloneUtils.cloneSerializable(response); truncateSalary(response); } Manipulator不过就是所谓的“高阶逻辑”。不过高阶逻辑虽然有抽象上的优势,也有不够直观,难于debug的问题。面对这么一个简单的需求,何必大炮打蚊子呢?(虽然,据说大炮和炮弹有现成的,不用额外买) 话说轮子,我感觉这个问题就是,本来要去隔壁,迈腿就到的,何必非要弄四个轮子开车?即使轮子白给,这车白开,不用你花钱加油。 |
|
返回顶楼 | |