锁定老帖子 主题:用enum代替if.这个设计大家怎么看
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-10-10
过度设计也是病。应该到真正应该重构的时候再重构,否则就是把本来简单的事情弄复杂,到时候别人看类结构就头晕,那比if else爆炸更头疼
|
|
返回顶楼 | |
发表时间:2012-10-10
cpszgy 写道 devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 所谓上梁不正下梁歪,不好的东西会传染的,好的东西也会传染。这样的设计如果一个刚接手的人被分配任务在此段代码上处理,多数情况是这样:晕啊,我不熟悉业务,如果我要重构有担心出问题而且工作量大,所以最好的方法再加一个if。 结果if越来越多,我们项目就是这样。 我只是就这段代码而言,那如果现实就是这么3种情况呢,以后又不会扩展了呢。那目前所做的工作的实用性有多大呢。所以说未来的情况未来再说,在没必要做修改的情况下做出的修改带来的效果又不是很明显,我觉得实在不必。那后面接手的人不愿意修改难道会怪原来的人写的考虑不周全么。如果当时的情况就只有2到3个if判断,我非弄个3 ,4个类出来,再来个继承什么的。代码是不是写的过于复杂了呢。 不要幻想后面的人能够下决心来重构,他自己不愿意(我来挣钱,干嘛做吃力不讨好的事),老板不同意(我花钱是让你做开发,不是来美化代码)。 再说了,代码量一大,错综复杂的调用关系,重构不是一个简单的任务! 所以说过度设计比不设计好很多。 至于判断以后会不会扩展,设计人员的判断了。我觉得本例子中以后会有从不同页面进来的情况出现。 |
|
返回顶楼 | |
发表时间:2012-10-10
最后修改:2012-10-10
devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 所谓上梁不正下梁歪,不好的东西会传染的,好的东西也会传染。这样的设计如果一个刚接手的人被分配任务在此段代码上处理,多数情况是这样:晕啊,我不熟悉业务,如果我要重构有担心出问题而且工作量大,所以最好的方法再加一个if。 结果if越来越多,我们项目就是这样。 我只是就这段代码而言,那如果现实就是这么3种情况呢,以后又不会扩展了呢。那目前所做的工作的实用性有多大呢。所以说未来的情况未来再说,在没必要做修改的情况下做出的修改带来的效果又不是很明显,我觉得实在不必。那后面接手的人不愿意修改难道会怪原来的人写的考虑不周全么。如果当时的情况就只有2到3个if判断,我非弄个3 ,4个类出来,再来个继承什么的。代码是不是写的过于复杂了呢。 不要幻想后面的人能够下决心来重构,他自己不愿意(我来挣钱,干嘛做吃力不讨好的事),老板不同意(我花钱是让你做开发,不是来美化代码)。 再说了,代码量一大,错综复杂的调用关系,重构不是一个简单的任务! 所以说过度设计比不设计好很多。 至于判断以后会不会扩展,设计人员的判断了。我觉得本例子中以后会有从不同页面进来的情况出现。 嘿,设计本身就是一个复杂的关系(设计模式怎么都得用2个以上的类把?),然后你每个不必要的地方都去过度设计,那不用代码量大,自己就把代码弄的错综复杂了。而且你怎么知道你的设计能正好适合以后的扩展?每种设计适合的扩张方面是不同的,有的地方能灵活有的灵活不起来。万一将来需要的改动正好和你的设计背离,那改起来更是伤经动骨,说不定就如你所说的,后来的人嫌麻烦也不跟你重构,到时候就会留下一个无比别扭的代码,恶心的要死。 |
|
返回顶楼 | |
发表时间:2012-10-10
对于他所说的情况跟本无解
只能等重写 |
|
返回顶楼 | |
发表时间:2012-10-10
albeter 写道 evanzzy 写道 albeter 写道 evanzzy 写道 albeter 写道 evanzzy 写道 if else是程序中避免不了的写法,为什么非要去掉呢?而且从理论上讲也去不掉啊。
这个修改我看没什么实际意义,而且策略模式也不是这样用的。真要把if else去掉,还是map来的实惠,和spring搭配,能够直接往map里面注入行为实现类,比这个写法好看得多。 我可没说一定要把if else去掉。并不是说把if去掉代码就多好了,但是有时候if/else过多会影响代码的可读性,也就是在特定的情况下过多的if能反应出一些问题.你说的策略模式不是这样用的,那请问你的意思是不应该使用枚举策略呢?还是在这个情景下不应该这样使用?以及原因? if else太多了当然不好,不过不是你这种解决办法。你这种办法只不过把if else的形式变了一下,翻译成汇编语言,还是一堆if else。你想想,如果有300个if else,那么你这个办法也要枚举300次,不对的。太多的分支,在java里面,就用map处理比较好,策略的实现类作为value注入到map里面,别说300个,300万个都可以的。 另外恕我技能拙劣,还真不知道有个叫枚举策略的写法,switch case倒是用过。策略模式是行为模式的一种,是以实现接口为基础的,不是你这样用的。 如果我们写程序的时候,第一反应是这个情况我应该用一种什么模式,那么证明你对设计模式还不熟悉,使用的时候就要慎重。 关于枚举策略的写法你可以参照effective java第二版的30条,另外策略模式通俗的理解可以理解为传递方法,接口实现只是实现该模式的一种具体方法,你可以比较下有指针的语言在实现策略模式的不同。另外也可以参照effective java第二版的21条。 Effective java2存在大量蛋疼的例子,在实践中根本遇不到,比如注释里面有\uXXXX会报错。比原来effective C++的水平差多了 就枚举策略这个用法来说thinking in java 中也有列举。既然两位大师都在自己的书中提到这个设计,我想这个设计会有些值得我们参考的地方。 Rod Johnson也是大师,而且是实践中证明过的大师。使用反向注入map的方式,既可以消灭if else,又可以不用那些蛋疼的模式,代码量也要小。说实话,大师所谓的枚举策略,还不如switch case来的直接和简单呢。要我说,3、5个if else根本没事儿,什么策略都不用,就写在那里就可以。而且,太多了的话,你要先检查一下设计了。 |
|
返回顶楼 | |
发表时间:2012-10-10
woshiykk1 写道 devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 所谓上梁不正下梁歪,不好的东西会传染的,好的东西也会传染。这样的设计如果一个刚接手的人被分配任务在此段代码上处理,多数情况是这样:晕啊,我不熟悉业务,如果我要重构有担心出问题而且工作量大,所以最好的方法再加一个if。 结果if越来越多,我们项目就是这样。 我只是就这段代码而言,那如果现实就是这么3种情况呢,以后又不会扩展了呢。那目前所做的工作的实用性有多大呢。所以说未来的情况未来再说,在没必要做修改的情况下做出的修改带来的效果又不是很明显,我觉得实在不必。那后面接手的人不愿意修改难道会怪原来的人写的考虑不周全么。如果当时的情况就只有2到3个if判断,我非弄个3 ,4个类出来,再来个继承什么的。代码是不是写的过于复杂了呢。 不要幻想后面的人能够下决心来重构,他自己不愿意(我来挣钱,干嘛做吃力不讨好的事),老板不同意(我花钱是让你做开发,不是来美化代码)。 再说了,代码量一大,错综复杂的调用关系,重构不是一个简单的任务! 所以说过度设计比不设计好很多。 至于判断以后会不会扩展,设计人员的判断了。我觉得本例子中以后会有从不同页面进来的情况出现。 嘿,设计本身就是一个复杂的关系(设计模式怎么都得用2个以上的类把?),然后你每个不必要的地方都去过度设计,那不用代码量大,自己就把代码弄的错综复杂了。而且你怎么知道你的设计能正好适合以后的扩展?每种设计适合的扩张方面是不同的,有的地方能灵活有的灵活不起来。万一将来需要的改动正好和你的设计背离,那改起来更是伤经动骨,说不定就如你所说的,后来的人嫌麻烦也不跟你重构,到时候就会留下一个无比别扭的代码,恶心的要死。 类似这样的场景是过度设计吗?我觉得不是。 设计好不好唯一的检验标准是可扩展性、可维护性、可理解性是否好。这个“好”每个人体验都不一样。 也许你觉得有个地方让我加个if代码块就好了。 相比楼主没有重构的代码,所谓的过度设计至少是经过思考的产物。那些做了过度设计的人至少渴望用OO的思想设计系统,人都是不断摸索才进步的。不会有因为过度设计而失败的系统,相反失败的系统多是没有设计的。 |
|
返回顶楼 | |
发表时间:2012-10-10
最后修改:2012-10-10
xiaoyu64814361 写道
albeter 写道
夜神月 写道
公司给你放假,还不出去玩,闲来无事你咋不去把妹子去呢,活脱一个屌丝
屌丝的命,没办法。
public class HandleSomething { private Manager manager; private Logger subLogger = LoggerFactory.getLogger(this.getClass()); protected void work( int entryType, long userId,Context context) { switch(entryType){ case 1: { context.put("type", vipFlow(userId,context)); return; } case 2:{ context.put("type", indexFlow(userId, context)); return; } case 3:{ context.put("type", othersFlow(userId,context)); } } } private int vipFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} private int indexFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} private int othersFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} }
1.重构成这样就足够了 很好懂了
2.如果能把所有 context 赋值操作挪到一起 不论是一个enum中 还是放在某个查表法中 完成context的赋值 代码就好读了.
3.如果 有manager 需要传入那么就应该把对应manager 传给 enum 中的 method去完成 有logger 也传入就可以了.
4.有可能if变多 很多时候把一个操作切片的代价就是if变多. 但由于一个类内是可以自解释的 所以读懂很简单.
PS:楼上众位. 你们说的东西太抽象了 取舍之间差别太模糊 不如写写这个代码看看怎么个清爽法? |
|
返回顶楼 | |
发表时间:2012-10-10
抛出异常的爱 写道
xiaoyu64814361 写道
albeter 写道
夜神月 写道
公司给你放假,还不出去玩,闲来无事你咋不去把妹子去呢,活脱一个屌丝
屌丝的命,没办法。
public class HandleSomething { private Manager manager; private Logger subLogger = LoggerFactory.getLogger(this.getClass()); protected void work( int entryType, long userId,Context context) { switch(entryType){ case 1: { context.put("type", vipFlow(userId,context)); return; } case 2:{ context.put("type", indexFlow(userId, context)); return; } case 3:{ context.put("type", othersFlow(userId,context)); } } } private int vipFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} private int indexFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} private int othersFlow(long userId, Context context) {/*这里的逻辑用到manager和subLogger*/} }
1.重构成这样就足够了 很好懂了
2.如果能把所有 context 赋值操作挪到一起 不论是一个enum中 还是放在某个查表法中 完成context的赋值 代码就好读了.
3.如果 有manager 需要传入那么就应该把对应manager 传给 enum 中的 method去完成 有logger 也传入就可以了.
4.有可能if变多 很多时候把一个操作切片的代价就是if变多. 但由于一个类内是可以自解释的 所以读懂很简单.
PS:楼上众位. 你们说的东西太抽象了 取舍之间差别太模糊 不如写写这个代码看看怎么个清爽法? 是的,"talk is cheap ,show me the code" |
|
返回顶楼 | |
发表时间:2012-10-11
说过度设计的人还是闭嘴吧,不要误导别人。多看看人家优秀的源代码,比如apache roller中有自己的任务调度框架,设计者怎么知道有人会拿他们的源代码做二次开发,而且也需要定时任务;再比如,roller应用velocity作为渲染页面引擎,怎么知道有人在二次开发式也需要velocity生成个性化的邮件、短信,而且还不用直接调用velocity的api?
人家roller可能也没有以后要换模版引擎,但是为什么人家还是设计为可切换呢?而且对其api进行封装,难道这些都是过度设计了吗? 对第三方软件进行封装的好处是可以却换到其他软件,解除应用自身代码对具体第三方软件api的依赖,方便以后可以切换,更主要的是可以提高工作效率,因为同个项目中其他人也用到这个第三方软件,只要一个人去深入研究并提高封装后的api即可。 所以,我们开发新项目不可能不用到第三方软件,比如水晶报表、poi等等这些要封装一下。也就是你们所谓的过度设计吧。 我参加的十几个项目,难以维护,不是因为过度设计,而是没有设计,随意写代码。 |
|
返回顶楼 | |
发表时间:2012-10-11
devroller2 写道 说过度设计的人还是闭嘴吧,不要误导别人。多看看人家优秀的源代码,比如apache roller中有自己的任务调度框架,设计者怎么知道有人会拿他们的源代码做二次开发,而且也需要定时任务;再比如,roller应用velocity作为渲染页面引擎,怎么知道有人在二次开发式也需要velocity生成个性化的邮件、短信,而且还不用直接调用velocity的api?
人家roller可能也没有以后要换模版引擎,但是为什么人家还是设计为可切换呢?而且对其api进行封装,难道这些都是过度设计了吗? 对第三方软件进行封装的好处是可以却换到其他软件,解除应用自身代码对具体第三方软件api的依赖,方便以后可以切换,更主要的是可以提高工作效率,因为同个项目中其他人也用到这个第三方软件,只要一个人去深入研究并提高封装后的api即可。 所以,我们开发新项目不可能不用到第三方软件,比如水晶报表、poi等等这些要封装一下。也就是你们所谓的过度设计吧。 我参加的十几个项目,难以维护,不是因为过度设计,而是没有设计,随意写代码。 不要不承认有过度设计这回事,如果没有这回事,也就不会有这个词 另外你举的例子真心好笑。像roller这样的,本身就是个运行框架,设计时不考虑扩展性的话,能玩得转吗?又比如maven,本身就是基于插件运作,那当然设计时也考虑扩展性。这些都是优秀设计,不是过度设计 至于你去封装poi,明显就是过度封装。没错,如果换了第三方组件,你自行封装那层的API是不受影响,问题是组件都换了,你封装那层不改就能跑吗?只是在哪里改的问题,你觉得你封装的API,一定比第三方组件的原生API好用吗? 设计是好的,但是过度设计是有问题的,并且要承认这个事实的存在 |
|
返回顶楼 | |