锁定老帖子 主题:用enum代替if.这个设计大家怎么看
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-10-10
albeter 写道 十一闲来无事到公司改了段代码,大家看看这个修改适合不。首先放出修改前的原始的代码(经过简化,改了名字,名字随便改的),逻辑很简单,就是前端传一个参数进来,后台根据参数的不同进行不同的逻辑处理。
public class HandleSomething { private Manager manager; private Logger subLogger = LoggerFactory.getLogger(this.getClass()); /** * entryType ,进入的参数,根据该参数来判断逻辑。 * */ public static final int VIP_ENTRY_FLOW = 1; // 特殊页面进入 public static final int INDEX_ENTRY_FLOW = 2; // 首页进入 public static final int OTHERS_ENTRY_FLOW = 3; // 其他页面进来 protected void work( int entryType, long userId,Context context) { if (entryType == VIP_ENTRY_FLOW) { context.put("type", vipFlow(userId,context)); return; } if (entryType == INDEX_ENTRY_FLOW) { context.put("type", indexFlow(userId, context)); return; } if (entryType == OTHERS_ENTRY_FLOW) { 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*/} } 修改后: public class HandleSomething { private static Manager manager; private static Logger subLogger = LoggerFactory.getLogger(HandleSomething.class); protected void work( int entryType, long userId,Context context) { for (Flow flow : Flow.values()) { if (flow.getTag() == entryType) { context.put("type", flow.handle(userId, context)); break; } } } enum Flow{ VIP_ENTRY_FLOW (1) {// 特殊页面进入 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ }, INDEX_ENTRY_FLOW (2) {// 首页进入 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ }, OTHERS_ENTRY_FLOW (3){ // 其他页面进来 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ } }; private final int tag; Flow(Integer tag){ this.tag=tag; } public int getTag() { return tag; } public abstract int handle(long userId, Context context); } } 修改后通过使用枚举类型间接地去掉了if. 我觉得修改之后有以下特点: 优点:1.execute方法的代码更简洁并且减少重复代码 2.如果要增加新的处理流程只需要在枚举类中增加一个参数类型即可,不用修改execute方法 但是我有个问题:不清楚这样写是否会带来其他问题。例如性能问题和内存问题。 不懂之一: int entryType 调用者需要知道具体数字对应的意思`` 不懂之二: WORK除了作了个再分类调用函数啥用处都没有 protected void flow( int entryType, long userId,Context context) ``共用代码 再if 调用不同代码或者函数 想法之三 如果不考虑性能,获得枚举名称字符串直接反射调用函数,用不着IF 想法之四 WORK里面连续调用三个函数 每个函数里面自己判断是不是自己的类型,也用不着IF |
|
返回顶楼 | |
发表时间:2012-10-10
模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 |
|
返回顶楼 | |
发表时间:2012-10-10
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++的水平差多了 |
|
返回顶楼 | |
发表时间:2012-10-10
cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 |
|
返回顶楼 | |
发表时间:2012-10-10
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 中也有列举。既然两位大师都在自己的书中提到这个设计,我想这个设计会有些值得我们参考的地方。 |
|
返回顶楼 | |
发表时间:2012-10-10
yippees 写道 albeter 写道 十一闲来无事到公司改了段代码,大家看看这个修改适合不。首先放出修改前的原始的代码(经过简化,改了名字,名字随便改的),逻辑很简单,就是前端传一个参数进来,后台根据参数的不同进行不同的逻辑处理。
public class HandleSomething { private Manager manager; private Logger subLogger = LoggerFactory.getLogger(this.getClass()); /** * entryType ,进入的参数,根据该参数来判断逻辑。 * */ public static final int VIP_ENTRY_FLOW = 1; // 特殊页面进入 public static final int INDEX_ENTRY_FLOW = 2; // 首页进入 public static final int OTHERS_ENTRY_FLOW = 3; // 其他页面进来 protected void work( int entryType, long userId,Context context) { if (entryType == VIP_ENTRY_FLOW) { context.put("type", vipFlow(userId,context)); return; } if (entryType == INDEX_ENTRY_FLOW) { context.put("type", indexFlow(userId, context)); return; } if (entryType == OTHERS_ENTRY_FLOW) { 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*/} } 修改后: public class HandleSomething { private static Manager manager; private static Logger subLogger = LoggerFactory.getLogger(HandleSomething.class); protected void work( int entryType, long userId,Context context) { for (Flow flow : Flow.values()) { if (flow.getTag() == entryType) { context.put("type", flow.handle(userId, context)); break; } } } enum Flow{ VIP_ENTRY_FLOW (1) {// 特殊页面进入 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ }, INDEX_ENTRY_FLOW (2) {// 首页进入 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ }, OTHERS_ENTRY_FLOW (3){ // 其他页面进来 @Override int handle(long userId, Context context) { /*这里的逻辑用到manager和subLogger*/ } }; private final int tag; Flow(Integer tag){ this.tag=tag; } public int getTag() { return tag; } public abstract int handle(long userId, Context context); } } 修改后通过使用枚举类型间接地去掉了if. 我觉得修改之后有以下特点: 优点:1.execute方法的代码更简洁并且减少重复代码 2.如果要增加新的处理流程只需要在枚举类中增加一个参数类型即可,不用修改execute方法 但是我有个问题:不清楚这样写是否会带来其他问题。例如性能问题和内存问题。 不懂之一: int entryType 调用者需要知道具体数字对应的意思`` 不懂之二: WORK除了作了个再分类调用函数啥用处都没有 protected void flow( int entryType, long userId,Context context) ``共用代码 再if 调用不同代码或者函数 想法之三 如果不考虑性能,获得枚举名称字符串直接反射调用函数,用不着IF 想法之四 WORK里面连续调用三个函数 每个函数里面自己判断是不是自己的类型,也用不着IF 想法三能不能给出具体的代码?想法四不失为一个设计的方法,但是这样设计感觉方法的责任太大了。每个方法应该只负责单独的业务处理。 |
|
返回顶楼 | |
发表时间:2012-10-10
package com.test;
import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; public class Tests { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Flow f=Flow.INDEX_ENTRY_FLOW; System.out.println(f.toString()); Tests tt=new Tests(); tt.all(f.INDEX_ENTRY_FLOW,"aaaaaaaaa"); tt.all(f.VIP_ENTRY_FLOW,"aaaaaaaaa"); } enum Flow{ VIP_ENTRY_FLOW, INDEX_ENTRY_FLOW } public void all(Flow f,String ss) { String s=f.toString(); Class clazz = this.getClass(); try { Method m2 = clazz.getDeclaredMethod(s, String.class); try { m2.invoke(this, ss); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void VIP_ENTRY_FLOW(String s) { System.out.println("VIP_ENTRY_FLOW"+s); } private void INDEX_ENTRY_FLOW(String s) { System.out.println("INDEX_ENTRY_FLOW"+s); } } 输出: INDEX_ENTRY_FLOWaaaaaaaaa VIP_ENTRY_FLOWaaaaaaaaa 乱写的一个例子 以前C#的时候用过 硬写了下 参考 你的方法本来就在类里面,真单独业务,那调用者直接调用子FLOW函数就行了`` |
|
返回顶楼 | |
发表时间:2012-10-10
devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 |
|
返回顶楼 | |
发表时间:2012-10-10
cpszgy 写道 devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 所谓上梁不正下梁歪,不好的东西会传染的,好的东西也会传染。这样的设计如果一个刚接手的人被分配任务在此段代码上处理,多数情况是这样:晕啊,我不熟悉业务,如果我要重构有担心出问题而且工作量大,所以最好的方法再加一个if。 结果if越来越多,我们项目就是这样。 |
|
返回顶楼 | |
发表时间:2012-10-10
devroller2 写道 cpszgy 写道 devroller2 写道 cpszgy 写道 模式最重要的一点就是不要为了模式而模式,
我觉得原来的代码的可读性和扩展的问题都不是特别大。 目前的重构确实没有多大的必要。如果到时候真的一下子超过5种情况了再重构也不迟。当让你用了enum我第一想到的是用switch去替换if,结果用了for。。。那还不如原来的。要是真重构,最好还是根据value值来自动生成不同对象。比较合理。 为了模式而模式有何不好?没有人凭空想象就能学到东西,这也许是一些人实践模式的学习方法。总之,楼主有想法,敢做,其中的体会只有做了的人才知道。而且比原来的代码要强一些。 不过话说回来,模式不过是实现OO目标的具体方法、途径而已,请抛开模式!设计时心中多想想你的代码如何做到符合OO的目标就可以了,如果达到OO的目标,你的代码自然接近于那些模式。 简单的东西能解决,就用简单的。没必要一个3个if判断就能解决的问题非要用个设计模式。而且用了模式后会会增加类层次和理解的复杂度。再说这里还没到非要用到需要重构的时候。目前这么使用if判断我觉得是丝毫没有问题。 所谓上梁不正下梁歪,不好的东西会传染的,好的东西也会传染。这样的设计如果一个刚接手的人被分配任务在此段代码上处理,多数情况是这样:晕啊,我不熟悉业务,如果我要重构有担心出问题而且工作量大,所以最好的方法再加一个if。 结果if越来越多,我们项目就是这样。 我只是就这段代码而言,那如果现实就是这么3种情况呢,以后又不会扩展了呢。那目前所做的工作的实用性有多大呢。所以说未来的情况未来再说,在没必要做修改的情况下做出的修改带来的效果又不是很明显,我觉得实在不必。那后面接手的人不愿意修改难道会怪原来的人写的考虑不周全么。如果当时的情况就只有2到3个if判断,我非弄个3 ,4个类出来,再来个继承什么的。代码是不是写的过于复杂了呢。 |
|
返回顶楼 | |