- 浏览: 452704 次
最新评论
-
carlos23:
我想知道用WriterLogger后,里面的writer在外面 ...
论面向组合子程序设计方法 之 燃烧的荆棘 -
marsyoung:
讲的什么。。没看懂。例子太抽象。。
论面向组合子程序设计方法 之 创世纪 -
wanghhao:
优雅的方式!
论面向组合子程序设计方法 之 微步毂纹生 -
ykdsg:
有源码吗?
论面向组合子程序设计方法 之 monad -
咱不怕:
如果在一个函数中多次使用到这个不变temp对象,按照Marti ...
关于 Replace Temp With Query
问题是这样的。
一个MyService类里面,有一个MyResponse runService()函数。这个runService函数会调用一个web service来得到MyResponse对象。这个MyResponse对象在runService()函数中被缓存,然后返回。
现在的目标是,在runService返回以前,先把MyResponse clone一下,然后如果MyResponse.getCensus().getSalary()返回的带有几毛几分的零钱,就把这个salary truncate成整数。
需求不难,一个直观的解决方案是:
CloneUtil是现成的。只要写一个SalaryTruncationUtil类就算完工了。
可是问题出现在,这个系统存在着一个ResponseManipulator接口(在另外一个package里面)。
ResponseManipulator的接口如下:
从签名上,可以看出一个ResponseManipulator负责操作一个MyResponse,然后返回一个新的(或者原来的MyResponse)对象。
同时,另外还现存一个ChainResponseManipulator类,它负责把若干个ResponseManipulator对象串起来:
以及一个已经写好的DeepCloneManipulator类来负责对一个Response对象的clone。
于是,我的pair决定这样写:
当然,还要实现一个TruncateSalaryManipulator。实现起来非常简单,就不写了。
我反对这个设计。虽然两者在代码量上不相伯仲,但是我认为这个设计无谓地增加复杂性,有一种绕着弯子解决简单问题的感觉。一个简单的顺序操作非要用一个特殊的接口和一个特殊的ChainResponseManipulator来实现。
一般来说,用接口是为了得到多态,降低耦合。可是在pair的代码里,该有的依赖一个没少,这个接口就显得意义寥寥。
而且这样做其实增大了MyService的依赖,因为凭空多了对ResponseManipulator和ChainResponseManipulator的依赖。
另外,ChainResponseManipulator对debug也不是非常友好,你单步运行每一个manipulator只能在ChainResponseManipulator的代码中,而不是MyService的代码中。
pair的观点有三:
1。看不出我的方案比用Manipulator有什么简单性的优势。
2。ChainResponseManipulator这一套设施已经存在,又不需要从头写。而且别人都是这么干的。
3。debug可以在每个不同的Manipulator类里面设置断点。
总而言之,没有达成一致意见。因为是pair主导键盘,所以最终pair的方案获胜。
今天在想怎么说服pair的时候,想了这么一个例子:
假设已经有一个StringAppender类:
那么在面对把两个对象连接成一个对象的时候,我们是:obj1.toString()+obj2.toString()呢?还是:new StringAppender(new Object[]{obj1, obj2}).toString()呢?
是不是已经有了的设施,为了保持一致性就必须要使用呢?即使有更简便的方法?
关于这个问题,你怎么看?
这话正点。如果manipulator是注射进来的话,我一点意见没有。
问题是绕了半天还要直接new出来,一点灵活性也没得到。这就像要计算1+2+3,不直接写,非要写成一个数组加循环:
这循环的好处是被计算的数据可以动态决定。可是如果你的数据本身是静态写死的,那么就不如直接1+2+3。
感觉说得很好,这才是真正的理由!
Manipulator在我看来本来就是个过度设计。
它的用法一直都是:
而这个设计相比于下面的代码好处非常有限:
就为了节省敲“manipulate(response)”在我看来不是一个引入一个接口和ChainManipulator的理由。
感觉还是用StringAppender好些。
并非是因为有了StringAppender才想到要用这个,而是因为有了
这样的表达式,才会想到要写一个StringAppender类的。
一个MyService类里面,有一个MyResponse runService()函数。这个runService函数会调用一个web service来得到MyResponse对象。这个MyResponse对象在runService()函数中被缓存,然后返回。
现在的目标是,在runService返回以前,先把MyResponse clone一下,然后如果MyResponse.getCensus().getSalary()返回的带有几毛几分的零钱,就把这个salary truncate成整数。
需求不难,一个直观的解决方案是:
java 代码
- MyResponse runService() {
- MyResponse response = call web service;
- cache response;
- response = (MyResponse)CloneUtil.cloneSerializable(response);
- SalaryTruncationUtil.truncateSalaryIfNecessary(response);
- return response;
- }
CloneUtil是现成的。只要写一个SalaryTruncationUtil类就算完工了。
可是问题出现在,这个系统存在着一个ResponseManipulator接口(在另外一个package里面)。
ResponseManipulator的接口如下:
java 代码
- public interface ResponseManipulator {
- MyResponse manipulate(MyResponse response);
- }
从签名上,可以看出一个ResponseManipulator负责操作一个MyResponse,然后返回一个新的(或者原来的MyResponse)对象。
同时,另外还现存一个ChainResponseManipulator类,它负责把若干个ResponseManipulator对象串起来:
java 代码
- public class ChainResponseManipulator implements ResponseManipulator {
- private ResponseManipulator[] manipulators;
- public MyResponse manipulate(MyResponse response){
- for(ResponseManipulator manipulator : manipulators) {
- response = manipulator.manipulate(response);
- }
- }
- }
于是,我的pair决定这样写:
java 代码
- MyResponse runService() {
- MyResponse response = call web service;
- cache response;
- response = getManipulator().manipulate(response);
- }
- ResponseMinipulator getManipulator() {
- return new ChainResponseManipulator(new ResponseManipulator[]{
- new DeepCloneManipulator(),
- new TruncateSalaryManipulator();
- });
- }
当然,还要实现一个TruncateSalaryManipulator。实现起来非常简单,就不写了。
我反对这个设计。虽然两者在代码量上不相伯仲,但是我认为这个设计无谓地增加复杂性,有一种绕着弯子解决简单问题的感觉。一个简单的顺序操作非要用一个特殊的接口和一个特殊的ChainResponseManipulator来实现。
一般来说,用接口是为了得到多态,降低耦合。可是在pair的代码里,该有的依赖一个没少,这个接口就显得意义寥寥。
而且这样做其实增大了MyService的依赖,因为凭空多了对ResponseManipulator和ChainResponseManipulator的依赖。
另外,ChainResponseManipulator对debug也不是非常友好,你单步运行每一个manipulator只能在ChainResponseManipulator的代码中,而不是MyService的代码中。
pair的观点有三:
1。看不出我的方案比用Manipulator有什么简单性的优势。
2。ChainResponseManipulator这一套设施已经存在,又不需要从头写。而且别人都是这么干的。
3。debug可以在每个不同的Manipulator类里面设置断点。
总而言之,没有达成一致意见。因为是pair主导键盘,所以最终pair的方案获胜。
今天在想怎么说服pair的时候,想了这么一个例子:
假设已经有一个StringAppender类:
java 代码
- class StringAppender {
- private Object[] objects;
- public String toString(){
- StringBuffer buf = new StringBuffer();
- for(Object obj : objects) {
- buf.append(obj);
- }
- return buf.toString();
- }
- }
是不是已经有了的设施,为了保持一致性就必须要使用呢?即使有更简便的方法?
关于这个问题,你怎么看?
评论
18 楼
dhxlsfn
2007-02-27
没有一定之规
17 楼
canonical
2007-02-26
这里需要区分是概念和实现。 我们所采取的办法是保持很直接很方便的方式直接调用实现代码,在需要的时候为实现代码增加概念包装类。实际上如果在系统架构上不存在通用的Manipulator的支持(例如动态配置,管理等),采用chain结构等并不是什么好主意。 很多情况下我们需要的是统一实现而不是概念依赖。
16 楼
ajoo
2007-02-26
intolong 写道
MyResponse runService()现在的实现逻辑是:
1. 调用Web Service得到MyResponse
2. 对MyResponse做一系列后续处理
如果后续处理是可能发生变化的,那么你pair的方案就灵活了,但不要自己查找ResponseMinipulator,而是DI进来,由组装代码负责这个变化。
如果后续处理是一定的,那么hardcode更直观和简洁。
1. 调用Web Service得到MyResponse
2. 对MyResponse做一系列后续处理
如果后续处理是可能发生变化的,那么你pair的方案就灵活了,但不要自己查找ResponseMinipulator,而是DI进来,由组装代码负责这个变化。
如果后续处理是一定的,那么hardcode更直观和简洁。
这话正点。如果manipulator是注射进来的话,我一点意见没有。
问题是绕了半天还要直接new出来,一点灵活性也没得到。这就像要计算1+2+3,不直接写,非要写成一个数组加循环:
int[] arr = {1,2,3}; int sum = 0; for(int i=0; i<arr.length; i++){ sum += arr[i]; }
这循环的好处是被计算的数据可以动态决定。可是如果你的数据本身是静态写死的,那么就不如直接1+2+3。
15 楼
intolong
2007-02-25
MyResponse runService()现在的实现逻辑是:
1. 调用Web Service得到MyResponse
2. 对MyResponse做一系列后续处理
如果后续处理是可能发生变化的,那么你pair的方案就灵活了,但不要自己查找ResponseMinipulator,而是DI进来,由组装代码负责这个变化。
如果后续处理是一定的,那么hardcode更直观和简洁。
1. 调用Web Service得到MyResponse
2. 对MyResponse做一系列后续处理
如果后续处理是可能发生变化的,那么你pair的方案就灵活了,但不要自己查找ResponseMinipulator,而是DI进来,由组装代码负责这个变化。
如果后续处理是一定的,那么hardcode更直观和简洁。
14 楼
cat
2007-02-11
我还是觉得简单地直接写出来比较好,容易理解,容易调试,效率似乎也更高。
题外话:看到过有一些component的所谓“data-driven”把什么都写到XML里面,最后XML里面可以配置Condition, And, Or, Not,Op,感觉就是在用XML写代码。写起来不方便不说,调试起来更是累人。
题外话:看到过有一些component的所谓“data-driven”把什么都写到XML里面,最后XML里面可以配置Condition, And, Or, Not,Op,感觉就是在用XML写代码。写起来不方便不说,调试起来更是累人。
13 楼
jellyfish
2007-02-08
The original design is very sound. Don't see this kind of coding often.
The original design fits the open-close principle.
The design is just a template pattern, as those interceptors in web apps, in a chain. It's a post processing of a complex method.
The very naive, and commonly seen, way to implement is through nested if-else blocks. This completely violates the OO principles.
The root reason is to make maintenance simple. If we started from nested if-else, when we add more if-else blocks, it's just so easy to break existing logic(especially those if-without-else blocks because they have implicit no-code default behaviors). One way to replace them is using interceptors. The interceptors, in a certain degree confine the individual post processing to their own classes so that we can change them independently.
In general, if we have less than 3(the magic number 3) postprocessings, we could hardcode them. But if there are 3 or more similar code patterns then we should definitely avoid it.
The nice thing about this design is that when you add even a simple requirement like this, you touch minimal original code(only the hook portion), plus the new code. A simple requirement is simple, but not 10 simple requirements, not when they interact each other, not when you need to apply them in 10 different places, not when they have heavy dependencies, not when 15 of them combines together.
If you think this is simple, it's because you are benefiting from the sound design. What if you are in a 15-level if-else block and you need to add another if-else there?
Even for a simple salary calculation, there could be many postprocessings, truncate to unit, currency conversion, add bonus, minus stock options, minus health insurrance, pay income tax, etc.
Even we use OO, this is still tough. First, there is an order in the sequence of postprocessings, who does first. For instance, health insurrance should be before income tax because it's "before tax". Then, there could be combination effect, e.g., you can't combine certain set of them. This makes testing very tedious because you need to test all combinations, make sure you get correct results or exceptions
OO is not just a textbook concept, it simplifies coding *and* maintenance. If you think it's overengineering, try inline them to see whether it's good or not. In this case, if you don't follow the original design, then what do you think the guy after you says?
There are several improvements to this design as well. If the creation of these postprocessors is complex, e.g., they have very heavy dependencies, then use a factory dedicated to the creation so that the dependencies won't spread everywhere(Spring is a nice candidate). Furthermore, the interface can be improved too, have two more methods:
initWith(response) - where we get values from response and inject all other dependencies, like get exchange rate for currencies.
isApplicable() - use the above method to determine whether we should apply this processor, based on the values from initWith() and others.
So not only this is a good approach, but we can make it more "OO", not because we like OO, instead because we want to separate things(like dependencies) out.
There are many similar examples in the real world, from web app interceptors for i18n conversion, currency conversion, validation, security, audit, logging, to simple spreadsheets(think about a data matrix as the response here and what we can do for columns and rows, scaling, number crunching, sum and %, etc)
In my experience, I had a case where I had 17 interceptors in 2 years(not knowing all of them upfront), sometimes I had only 10 minutes to add one under heavy pressure. Their combinations are very tricky, the first output(like response) could come from 3 different paths, each of them has heavy dependencies. This design stands well.
When we code, we have to think about how to maintain them. This is not college student homework, which can be thrown away after tests, :-). We may do simple things once or twice, but not more than that.
Just my experience, no point fingers.
The original design fits the open-close principle.
The design is just a template pattern, as those interceptors in web apps, in a chain. It's a post processing of a complex method.
The very naive, and commonly seen, way to implement is through nested if-else blocks. This completely violates the OO principles.
The root reason is to make maintenance simple. If we started from nested if-else, when we add more if-else blocks, it's just so easy to break existing logic(especially those if-without-else blocks because they have implicit no-code default behaviors). One way to replace them is using interceptors. The interceptors, in a certain degree confine the individual post processing to their own classes so that we can change them independently.
In general, if we have less than 3(the magic number 3) postprocessings, we could hardcode them. But if there are 3 or more similar code patterns then we should definitely avoid it.
The nice thing about this design is that when you add even a simple requirement like this, you touch minimal original code(only the hook portion), plus the new code. A simple requirement is simple, but not 10 simple requirements, not when they interact each other, not when you need to apply them in 10 different places, not when they have heavy dependencies, not when 15 of them combines together.
If you think this is simple, it's because you are benefiting from the sound design. What if you are in a 15-level if-else block and you need to add another if-else there?
Even for a simple salary calculation, there could be many postprocessings, truncate to unit, currency conversion, add bonus, minus stock options, minus health insurrance, pay income tax, etc.
Even we use OO, this is still tough. First, there is an order in the sequence of postprocessings, who does first. For instance, health insurrance should be before income tax because it's "before tax". Then, there could be combination effect, e.g., you can't combine certain set of them. This makes testing very tedious because you need to test all combinations, make sure you get correct results or exceptions
OO is not just a textbook concept, it simplifies coding *and* maintenance. If you think it's overengineering, try inline them to see whether it's good or not. In this case, if you don't follow the original design, then what do you think the guy after you says?
There are several improvements to this design as well. If the creation of these postprocessors is complex, e.g., they have very heavy dependencies, then use a factory dedicated to the creation so that the dependencies won't spread everywhere(Spring is a nice candidate). Furthermore, the interface can be improved too, have two more methods:
initWith(response) - where we get values from response and inject all other dependencies, like get exchange rate for currencies.
isApplicable() - use the above method to determine whether we should apply this processor, based on the values from initWith() and others.
So not only this is a good approach, but we can make it more "OO", not because we like OO, instead because we want to separate things(like dependencies) out.
There are many similar examples in the real world, from web app interceptors for i18n conversion, currency conversion, validation, security, audit, logging, to simple spreadsheets(think about a data matrix as the response here and what we can do for columns and rows, scaling, number crunching, sum and %, etc)
In my experience, I had a case where I had 17 interceptors in 2 years(not knowing all of them upfront), sometimes I had only 10 minutes to add one under heavy pressure. Their combinations are very tricky, the first output(like response) could come from 3 different paths, each of them has heavy dependencies. This design stands well.
When we code, we have to think about how to maintain them. This is not college student homework, which can be thrown away after tests, :-). We may do simple things once or twice, but not more than that.
Just my experience, no point fingers.
12 楼
jianfeng008cn
2007-02-07
hermitte 写道
这种情况很经常遇到,一般是根据项目的规模和时间来决定
刚开始编程的时候,我是吸收的J道那里的banq的思路。
就是在自己的业务层中,只调用更下层的代码,而不是复用已经有了的同层代码。
如果业务简单,就自己写一遍。
如果必须引用已经有了的同层代码,因为度量和减少代码冗余以便维护的缘故,我倾向于用Adapter或者Mediater模式,用接口封装和重构同层的代码。而不是直接引用其它人写的包的东西。
引用之前,把别人的类给包装下先。因为不知道其它人在编写代码的时候,会不会修改已经编写好的类,如果你依赖了他,然而在不知情的情况下,其它人又对你依赖的类进行了修改,就会非常麻烦。所以用结构型设计模式进行下解耦,是面向对象编程的一个基本功。
如果是原来,我倾向你的解决方案。因为那个符合“好莱坞原则”还有Banq的无为的道的思想。那个思想对我影响比较深刻。而且你的代码是高聚合,低耦合的。毕竟复用和耦合,在某种情况下是存在矛盾的。
不过现在我觉得OO这套有点过时了,有时候OO到成了代码复用的障碍,那个第二个应该用的是IOC的思路在里面,不过问题是由于JAVA接口方面的限制,反而导致耦合的加强,这个应该是JAVA语法的原因,不是编程的原因,毕竟依赖的只是接口而已。
刚开始编程的时候,我是吸收的J道那里的banq的思路。
就是在自己的业务层中,只调用更下层的代码,而不是复用已经有了的同层代码。
如果业务简单,就自己写一遍。
如果必须引用已经有了的同层代码,因为度量和减少代码冗余以便维护的缘故,我倾向于用Adapter或者Mediater模式,用接口封装和重构同层的代码。而不是直接引用其它人写的包的东西。
引用之前,把别人的类给包装下先。因为不知道其它人在编写代码的时候,会不会修改已经编写好的类,如果你依赖了他,然而在不知情的情况下,其它人又对你依赖的类进行了修改,就会非常麻烦。所以用结构型设计模式进行下解耦,是面向对象编程的一个基本功。
如果是原来,我倾向你的解决方案。因为那个符合“好莱坞原则”还有Banq的无为的道的思想。那个思想对我影响比较深刻。而且你的代码是高聚合,低耦合的。毕竟复用和耦合,在某种情况下是存在矛盾的。
不过现在我觉得OO这套有点过时了,有时候OO到成了代码复用的障碍,那个第二个应该用的是IOC的思路在里面,不过问题是由于JAVA接口方面的限制,反而导致耦合的加强,这个应该是JAVA语法的原因,不是编程的原因,毕竟依赖的只是接口而已。
感觉说得很好,这才是真正的理由!
11 楼
ajoo
2007-02-07
BirdGu 写道
ResponseManipulator是原来就存在的,那么为什么会有这个机制呢?你确定你现在的情况不属于ResponseManipulator原来设计要处理的问题吗?
Manipulator在我看来本来就是个过度设计。
它的用法一直都是:
void f(){ ... response = getManipulator().manipulate(response); ... } ResponseManipulator getManipulator(){ return new ChainManipulator(new ResponseManipulator[]{ new Manipulator1(), new Manipulator2() }); }
而这个设计相比于下面的代码好处非常有限:
void f(){ ... response = manipulate(response); ... } Response manipulate(Response response){ response = Manipulator1.doSomething(response); response = Manipulator2.doSomethingElse(response); }
就为了节省敲“manipulate(response)”在我看来不是一个引入一个接口和ChainManipulator的理由。
10 楼
BirdGu
2007-02-07
ResponseManipulator是原来就存在的,那么为什么会有这个机制呢?你确定你现在的情况不属于ResponseManipulator原来设计要处理的问题吗?
9 楼
ajoo
2007-02-07
灵活度看怎么说了。
就在我们要完成这个功能的时候,我忽然想到:如果不需要truncate,那么根本就没必要clone。
跟同事一说,他愣了半天。因为要实现这个功能ChainManipulator就不好使了。最后只好说,先这么放着,如果真有效率问题再说。
其实这个功能如果不用Manipulator,非常简单。不过就是:
Manipulator不过就是所谓的“高阶逻辑”。不过高阶逻辑虽然有抽象上的优势,也有不够直观,难于debug的问题。面对这么一个简单的需求,何必大炮打蚊子呢?(虽然,据说大炮和炮弹有现成的,不用额外买)
话说轮子,我感觉这个问题就是,本来要去隔壁,迈腿就到的,何必非要弄四个轮子开车?即使轮子白给,这车白开,不用你花钱加油。
就在我们要完成这个功能的时候,我忽然想到:如果不需要truncate,那么根本就没必要clone。
跟同事一说,他愣了半天。因为要实现这个功能ChainManipulator就不好使了。最后只好说,先这么放着,如果真有效率问题再说。
其实这个功能如果不用Manipulator,非常简单。不过就是:
if(needsTruncation(response)){ response = CloneUtils.cloneSerializable(response); truncateSalary(response); }
Manipulator不过就是所谓的“高阶逻辑”。不过高阶逻辑虽然有抽象上的优势,也有不够直观,难于debug的问题。面对这么一个简单的需求,何必大炮打蚊子呢?(虽然,据说大炮和炮弹有现成的,不用额外买)
话说轮子,我感觉这个问题就是,本来要去隔壁,迈腿就到的,何必非要弄四个轮子开车?即使轮子白给,这车白开,不用你花钱加油。
8 楼
shaucle
2007-02-05
<br/>
<strong>firebody 写道:</strong><br/>
<div class='quote_div'>光从这里的代码来看,看不出两个方案的优劣来,不过你的pair的方案确实存在“误用”<span><span>的嫌疑: 代码依赖于</span></span><span><span>ChainResponseManipulator这个类。<br/>
<br/>
但是,如果考虑别的</span></span>Service也需要你写的 功能的话,别人可能会这样调用:<br/>
<br/>
<ol class='dp-j'>
<li class='alt'><span><span>MyResponse runService() { </span></span> </li>
<li class=''><span> MyResponse response = call web service; </span> </li>
<li class='alt'><span> cache response; </span> </li>
<li class=''><span> response = ManupilatorFactory.getManupulate(</span><span><span>ResponseManipulator .A,</span></span><span><span>ResponseManipulator .B) </span></span><span>.manipulate(response); </span> </li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的话,可能会发挥一点 <span><span>ResponseManipulator 的作用。 <br/>
<br/>
不过光从代码来看,可能也不会比你的方法少到哪里去。<br/>
<br/>
一种比较实在的写法可以这样:<br/>
<br/>
<br/>
</span></span><br/>
<ol class='dp-j'>
<li class='alt'><span><span>MyResponse runService() { </span></span> </li>
<li class=''><span> MyResponse response = call web service; </span> </li>
<li class='alt'><span> cache response; <br/>
</span></li>
<li class='alt'><span>//first ly<br/>
</span></li>
<li class=''><span> response = ManupuateSupport.manipuate1(response)</span><span>;</span> </li>
</ol>
//secondly
<ol class='dp-j'>
<li class=''><span> response = ManupuateSupport.manipuate2(response)</span><span>;</span> </li>
<li class=''><span> </span> </li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的写法一样可以达到代码复用的好处。 <br/>
<br/>
上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 <br/>
<br/>
两者,放在不同的环境里面,或许有各自的用处把。</div>
<p><br/>
<br/>
<br/>
<br/>
我选择第一种,</p>
<p>第一种也可以有灵活度,</p>
<p>如: ManupuateSupport.add(MyResponse...)<span>;</span></p>
<p><span>ManupuateSupport.addAndManipulate(MyResponse...)<span>;</span></span></p>
<p><span><span>还可以有batch或readConfig等等</span></span></p>
<strong>firebody 写道:</strong><br/>
<div class='quote_div'>光从这里的代码来看,看不出两个方案的优劣来,不过你的pair的方案确实存在“误用”<span><span>的嫌疑: 代码依赖于</span></span><span><span>ChainResponseManipulator这个类。<br/>
<br/>
但是,如果考虑别的</span></span>Service也需要你写的 功能的话,别人可能会这样调用:<br/>
<br/>
<ol class='dp-j'>
<li class='alt'><span><span>MyResponse runService() { </span></span> </li>
<li class=''><span> MyResponse response = call web service; </span> </li>
<li class='alt'><span> cache response; </span> </li>
<li class=''><span> response = ManupilatorFactory.getManupulate(</span><span><span>ResponseManipulator .A,</span></span><span><span>ResponseManipulator .B) </span></span><span>.manipulate(response); </span> </li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的话,可能会发挥一点 <span><span>ResponseManipulator 的作用。 <br/>
<br/>
不过光从代码来看,可能也不会比你的方法少到哪里去。<br/>
<br/>
一种比较实在的写法可以这样:<br/>
<br/>
<br/>
</span></span><br/>
<ol class='dp-j'>
<li class='alt'><span><span>MyResponse runService() { </span></span> </li>
<li class=''><span> MyResponse response = call web service; </span> </li>
<li class='alt'><span> cache response; <br/>
</span></li>
<li class='alt'><span>//first ly<br/>
</span></li>
<li class=''><span> response = ManupuateSupport.manipuate1(response)</span><span>;</span> </li>
</ol>
//secondly
<ol class='dp-j'>
<li class=''><span> response = ManupuateSupport.manipuate2(response)</span><span>;</span> </li>
<li class=''><span> </span> </li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的写法一样可以达到代码复用的好处。 <br/>
<br/>
上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 <br/>
<br/>
两者,放在不同的环境里面,或许有各自的用处把。</div>
<p><br/>
<br/>
<br/>
<br/>
我选择第一种,</p>
<p>第一种也可以有灵活度,</p>
<p>如: ManupuateSupport.add(MyResponse...)<span>;</span></p>
<p><span>ManupuateSupport.addAndManipulate(MyResponse...)<span>;</span></span></p>
<p><span><span>还可以有batch或readConfig等等</span></span></p>
7 楼
firebody
2007-02-05
光从这里的代码来看,看不出两个方案的优劣来,不过你的pair的方案确实存在“误用”<span><span>的嫌疑: 代码依赖于</span></span><span><span>ChainResponseManipulator这个类。<br/>
<br/>
但是,如果考虑别的</span></span>Service也需要你写的 功能的话,别人可能会这样调用:<br/>
<br/>
<ol class='dp-j' start='1'>
<li class='alt'><span><span>MyResponse runService() { </span></span></li>
<li class=''><span> MyResponse response = call web service; </span></li>
<li class='alt'><span> cache response; </span></li>
<li class=''><span> response = ManupilatorFactory.getManupulate(</span><span><span>ResponseManipulator .A,</span></span><span><span>ResponseManipulator .B) </span></span><span>.manipulate(response); </span></li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的话,可能会发挥一点 <span><span>ResponseManipulator 的作用。 <br/>
<br/>
不过光从代码来看,可能也不会比你的方法少到哪里去。<br/>
<br/>
一种比较实在的写法可以这样:<br/>
<br/>
<br/>
</span></span> <br/>
<ol class='dp-j' start='1'>
<li class='alt'><span><span>MyResponse runService() { </span></span></li>
<li class=''><span> MyResponse response = call web service; </span></li>
<li class='alt'><span> cache response; <br/>
</span></li>
<li class='alt'><span>//first ly<br/>
</span></li>
<li class=''><span> response = ManupuateSupport.manipuate1(response)</span><span>;</span></li>
</ol>
//secondly
<ol class='dp-j' start='1'>
<li class=''><span> response = ManupuateSupport.manipuate2(response)</span><span>;</span></li>
<li class=''><span> </span></li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的写法一样可以达到代码复用的好处。 <br/>
<br/>
上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 <br/>
<br/>
两者,放在不同的环境里面,或许有各自的用处把。
<br/>
但是,如果考虑别的</span></span>Service也需要你写的 功能的话,别人可能会这样调用:<br/>
<br/>
<ol class='dp-j' start='1'>
<li class='alt'><span><span>MyResponse runService() { </span></span></li>
<li class=''><span> MyResponse response = call web service; </span></li>
<li class='alt'><span> cache response; </span></li>
<li class=''><span> response = ManupilatorFactory.getManupulate(</span><span><span>ResponseManipulator .A,</span></span><span><span>ResponseManipulator .B) </span></span><span>.manipulate(response); </span></li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的话,可能会发挥一点 <span><span>ResponseManipulator 的作用。 <br/>
<br/>
不过光从代码来看,可能也不会比你的方法少到哪里去。<br/>
<br/>
一种比较实在的写法可以这样:<br/>
<br/>
<br/>
</span></span> <br/>
<ol class='dp-j' start='1'>
<li class='alt'><span><span>MyResponse runService() { </span></span></li>
<li class=''><span> MyResponse response = call web service; </span></li>
<li class='alt'><span> cache response; <br/>
</span></li>
<li class='alt'><span>//first ly<br/>
</span></li>
<li class=''><span> response = ManupuateSupport.manipuate1(response)</span><span>;</span></li>
</ol>
//secondly
<ol class='dp-j' start='1'>
<li class=''><span> response = ManupuateSupport.manipuate2(response)</span><span>;</span></li>
<li class=''><span> </span></li>
<li class='alt'><span>} <br/>
</span></li>
</ol>
<br/>
这样的写法一样可以达到代码复用的好处。 <br/>
<br/>
上面一种写法,把这种Response manipulate的设计上升到一个架构的高度,但是后一种是比较聪明的实用的角度。 <br/>
<br/>
两者,放在不同的环境里面,或许有各自的用处把。
6 楼
pupi
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类的。
5 楼
hermitte
2007-02-04
这种情况很经常遇到,一般是根据项目的规模和时间来决定
刚开始编程的时候,我是吸收的J道那里的banq的思路。
就是在自己的业务层中,只调用更下层的代码,而不是复用已经有了的同层代码。
如果业务简单,就自己写一遍。
如果必须引用已经有了的同层代码,因为度量和减少代码冗余以便维护的缘故,我倾向于用Adapter或者Mediater模式,用接口封装和重构同层的代码。而不是直接引用其它人写的包的东西。
引用之前,把别人的类给包装下先。因为不知道其它人在编写代码的时候,会不会修改已经编写好的类,如果你依赖了他,然而在不知情的情况下,其它人又对你依赖的类进行了修改,就会非常麻烦。所以用结构型设计模式进行下解耦,是面向对象编程的一个基本功。
如果是原来,我倾向你的解决方案。因为那个符合“好莱坞原则”还有Banq的无为的道的思想。那个思想对我影响比较深刻。而且你的代码是高聚合,低耦合的。毕竟复用和耦合,在某种情况下是存在矛盾的。
不过现在我觉得OO这套有点过时了,有时候OO到成了代码复用的障碍,那个第二个应该用的是IOC的思路在里面,不过问题是由于JAVA接口方面的限制,反而导致耦合的加强,这个应该是JAVA语法的原因,不是编程的原因,毕竟依赖的只是接口而已。
刚开始编程的时候,我是吸收的J道那里的banq的思路。
就是在自己的业务层中,只调用更下层的代码,而不是复用已经有了的同层代码。
如果业务简单,就自己写一遍。
如果必须引用已经有了的同层代码,因为度量和减少代码冗余以便维护的缘故,我倾向于用Adapter或者Mediater模式,用接口封装和重构同层的代码。而不是直接引用其它人写的包的东西。
引用之前,把别人的类给包装下先。因为不知道其它人在编写代码的时候,会不会修改已经编写好的类,如果你依赖了他,然而在不知情的情况下,其它人又对你依赖的类进行了修改,就会非常麻烦。所以用结构型设计模式进行下解耦,是面向对象编程的一个基本功。
如果是原来,我倾向你的解决方案。因为那个符合“好莱坞原则”还有Banq的无为的道的思想。那个思想对我影响比较深刻。而且你的代码是高聚合,低耦合的。毕竟复用和耦合,在某种情况下是存在矛盾的。
不过现在我觉得OO这套有点过时了,有时候OO到成了代码复用的障碍,那个第二个应该用的是IOC的思路在里面,不过问题是由于JAVA接口方面的限制,反而导致耦合的加强,这个应该是JAVA语法的原因,不是编程的原因,毕竟依赖的只是接口而已。
4 楼
dennis_zane
2007-02-04
如果从编码风格一致性来讲,既然已经有现成的基础设施,那使用既有代码无可厚非,而且从维护者角度考虑,一致的写法更为友好。
3 楼
galaxystar
2007-02-04
已经有轮子了,嫌老的轮子磨损太严重!那么可以重新造一只!
成本论,如果在赛场上,你领先其他人很多圈,那么有时间造一只全新的,也无可厚非!
但是如果你没时间,还是跑完全程再说吧!
复杂程度来说,前者肯定复杂!
成本论,如果在赛场上,你领先其他人很多圈,那么有时间造一只全新的,也无可厚非!
但是如果你没时间,还是跑完全程再说吧!
复杂程度来说,前者肯定复杂!
2 楼
bencode
2007-02-04
我同意 pojo 这一观点
不过我觉得从代码的维护角度讲, 简单的那种很容易让人理解.
而采用现成的 Manipulator , 写出来的代码, 让人看起来有点点 "玄".
不过我觉得从代码的维护角度讲, 简单的那种很容易让人理解.
而采用现成的 Manipulator , 写出来的代码, 让人看起来有点点 "玄".
1 楼
pojo
2007-02-04
我觉得两种做法是半斤八两。如果系统没有现成的Manipulator的,那当然用简单的。现在已经有了Manipulator,少用一次多用一次并不改变依赖性。无可无不可的事,当然就是谁主导就听谁的,否则一起共事会很难过的。
发表评论
-
getThis().getEvilAdvocate().setDead(getTrue())
2008-08-14 04:15 3683code review过程中,看到这样的代码: Pair& ... -
怎样最有效地测试异常?
2008-04-02 21:56 4848工作中,和同事对测试 ... -
DRY与简单性的平衡
2007-02-16 18:45 5583这个事例说起来相当简单。不过小中见大,它大致体现了我和pair ... -
Web AOP?
2007-02-16 11:12 6142今天这个其实不是争论。 这是我接手的一个web系统的一个设计 ... -
依赖是否可以作为一个独立的衡量软件质量的标准?
2007-02-12 05:03 8061这个争论的背景有点复杂。我就尽量简化了说。 遗留系统有一个自 ... -
这样代码重用?
2007-02-12 03:09 19520这是一个工作中遇到的 ... -
jdbc还是ibatis?
2007-02-06 03:59 31760公司的一个大系统的持久层一直是直接使用jdbc。在jdbc的基 ... -
一致性和Use Right Tool For Right Job哪个重要?
2007-02-05 12:52 5574这个争执发生在测试的时候。 背景是这样的: 一个接口有很多乱七 ... -
关于 Replace Temp With Query
2007-02-05 11:55 8821这个I disagree系列里面我 ...
相关推荐
MATLAB是一款强大的数学计算软件,广泛应用于科学研究和工程计算领域。在复杂网络研究中,MATLAB也提供了专门...无论是初学者还是经验丰富的研究人员,都能从中受益,提升工作效率,推动复杂网络领域的理论和实践进步。
在IT领域,复杂网络是一种研究复杂系统相互连接方式的理论工具,它涵盖了生物学、社会学、互联网、电力网格等多个学科。MATLAB作为一种强大的数学计算和可视化软件,是实现复杂网络模型的理想平台。本资料包“复杂...
本文将深入探讨如何使用EasyExcel实现动态导出复杂表头的功能,结合给定的压缩包文件中的代码示例进行解析。 首先,我们要理解EasyExcel的基本概念。EasyExcel是一个基于Java的轻量级库,它设计的目标是处理大数据...
复杂网络的研究不仅仅局限于理论,它在社交网络、互联网、交通网络、生物网络等多个领域有着广泛的应用。理解复杂网络的基本理论和模型,对于认识和掌握这些实际网络的运行规律具有重要意义。通过学习复杂网络基础...
虽然压缩包内的文件名为“赚钱项目”,这可能是一个不完全相关的文件或者文档,但根据标题和描述,我们可以推测这个文件可能是与Java开发相关的项目案例,或者是一个能帮助开发者通过提升技能来提高工作效率或收入的...
matlab 复杂网络工具箱,实现复杂网络基本算法的源代码。
这个现象揭示了网络中的不平等性和核心-边缘结构。 4. **中心性(Centrality)**:中心性是衡量节点在网络中重要性的指标,包括度中心性、接近中心性、介数中心性和特征向量中心性等。度中心性是最简单的,指的是...
辩称,缺陷的全息复杂性将动作与体积区分开来。 基于他们的工作,我们在带边界的共形场论中研究了量子态的复杂性。 在通用二维BCFT中,我们进行了路径积分优化,它给出了复杂性的场理论定义之一。 我们还对高柳市的...
在一些复杂的应用场景中,我们可能需要实现更高级的功能,如复杂的表头和跨行列表体。这个主题主要关注如何利用`JTable`实现这些特性。 **1. 复杂表头** 复杂表头指的是具有多级或者分组的表头,这在处理具有层次...
复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂性中的思维.复杂...
复杂电磁环境的产生不仅仅是电磁辐射的物理叠加,更涉及到战场上的用频装备之间的相互作用和影响,形成一种类似生物群落中复杂气味的现象。 在研究复杂电磁环境时,我们需要关注以下几个方面: 1. **生成系统**:...
30 丨 装饰器模式:如何优化电商系统中复杂的商品价格策略?.html
代码 复杂网络BA算法计算过程代码代码 复杂网络BA算法计算过程代码代码 复杂网络BA算法计算过程代码代码 复杂网络BA算法计算过程代码代码 复杂网络BA算法计算过程代码代码 复杂网络BA算法计算过程代码代码 复杂网络...
问题中涉及的因素可能没有完全包含在专业工程实践的标准和规范中,同时问题相关各方的利益也可能不完全一致。最终,复杂工程问题具有较高的综合性,包含多个相互关联的子问题。 在教学实施案例中,上海交通大学的陈...
复杂控制系统 复杂控制系统复杂控制系统 复杂控制系统 复杂控制系统
《复杂网络上的动力学过程》是一本深入探讨复杂网络中动力学行为的专著,它在图学习领域具有重要的前期指导...通过学习这本书,你将能够运用复杂网络理论解决实际问题,无论是在生物科学、信息科学还是社会科学领域。
复杂网络是指具有非平凡拓扑结构的网络,其节点和边分布不遵循传统随机网络模型,如Erdős-Rényi模型或Boltzmann机模型。复杂网络的研究涵盖了生物学、社会学、经济学等多个领域,典型实例包括互联网、社交网络、...
论文研究-基于不等概率抽样的不完全信息条件下复杂网络抗毁性模型.pdf, 为了填补随机失效与故意攻击之间的空白,将复杂网络攻击信息的获取抽象成无放回的不等概率抽样...
在Android平台上开发一个复杂计算器,不仅需要扎实的编程基础,还需要对用户界面设计有深入理解。这个项目旨在帮助初学者掌握Android应用开发的基本技巧,并通过实现一个包含正弦、余弦等数学函数的计算器,进一步...