有时候代码中会遇到大段的if else语句,灰常的不优雅,就算没有强迫症的人,也必定除之而后快。在java中,都有哪些方式能去除那些if else呢?
首先要明确的是,实践而言,并不是只要有大段的if else语句就一定需要优化,在开始的时候,如果这里的逻辑比较清楚简单,而且也没有预期到一些业务逻辑会产生变动,那么其实就并不需要,起码是并不急着需要去优化这个if else语句。
当判断到确实需要优化if else,方法有很多,总结如下。
- 使用map.
- 使用枚举.
- 多态. 当然,设计模式实际上就是多态,而且理论上,大部分的设计模式都能用于优化if else,可以根据具体情况处理。
当if else代码段中的逻辑比较多和复杂的时候,可以适当的使用方法或者类封装好处理逻辑,然后使用反射来根据不同条件匹配对应处理方法或处理类。
下面举例。
要优化的原if else语句:1
2
3
4
5
6
7int code;
if("Name".equals(str))
code = 0;
else if("Age".equals(str))
code = 1;
else if("Address".equals(str))
code = 2;
使用map优化
1 | public final static Map map = new HashMap(); |
使用枚举优化
1 | public enum Codes { |
使用多态优化
1 | ICode iCode = (ICode)Class.forName("com.xxx." + str).newInstance(); |
“责任链”如何优化if else?
首先,既然每个if分支后面跟着一堆复杂的逻辑,每个分支里做的事情肯定不同,把它们堆在一个方法中并不妥当(如果楼主想讨论为什么不妥当,可以另外讨论,最常见的不妥当是因为各个分支的抽象层次不同导致阅读者思路混乱)。因此最好把各个分支的处理代码分别抽出来,分别形成独立的方法。这样每个分支处理都有明确的边界,而且我们可以在方法上写javadoc,形成良好的文档。
好,现在你有了一个单纯含有if分支的主控方法和一堆执行处理的方法,你面临的第二个问题是每个方法上都要传入一大串参数,因为原来的复杂处理往往依赖大量的上下文状态。解决这个问题的最正统有效(未必优雅)的方法是创建一个上下文(Context)类,或者也可以叫请求(Request)类来携带传入参数。这样可以解决参数文档问题,默认值问题和参数顺序问题。但你有许多个执行方法,显然你不会傻到为每个方法都创建一个上下文,而会只创建一个上下文类,每个方法都接收这个上下文实例,只取自己真正关注的属性。毕竟既然这些执行方法都从一个if结构中抽取处理,这些属性之间逻辑上总有些关联,放在一起也不会有很大问题。
现在你有了一堆参数一致,但名称不同的方法。如果你的需求变动不大,就这样就可以了。但如果你觉得需求可能会有变化,未来可能需要覆盖其中一些方法。你会发现,如果需求1需要你覆盖A,你需要创建一个子类。需求2需要你覆盖B,又要创建一个子类。需求3需要你同时具有需求A,需求B的特性,你又要创建一个子类。既然这样,何不把它们抽到独立的类中,可以分别扩展? 抽取过程中,你发现现在每个处理类都只有一个方法,方法名和类名是重复的。而且本质上它们都是某种处理器(Handler),何不让它们实现统一的接口,方法名统一改为handle。强调一下,这一步是预期需求会有变化的情况才做,如果认为需求不太可能会变化,或者预计变化有足够时间重构,完全可以在前一步就停止。
好,现在你有一个主控方法,这个方法创建一个上下文对象,再根据分支条件分别调用不同Handler子类上的handle方法,传入这个上下文。你注意到一个问题,分支条件本身和对应的处理逻辑是内聚的。如果条件发生变化,处理往往也要发生变化。反之依然。而且你读代码时,读到一个复杂的条件,往往不能轻易看出它要判断什么,这时最好的方法就是直接看看对应Handler的命名和文档,从处理方式反推这个条件对应的业务需求。既然这样,何不干脆把条件都搬到Handler里去,让每个Handler根据传入的上下文,看看在当前状态下自己是否应该执行处理。
现在你得到了一个主控类,这个类持有一堆Handler实例,主控类创建一个上下文,然后把上下文依次传给各个Handler,Handler自行判断是否应该执行自己的处理。
到了这一步,其实已经差不多了。不过对于某些人,他在进行前一步的重构时,就会醒悟:主控类现在已经变成了一个单纯的任务转发人(分配者)。它根本没有必要持有一个Handler的列表再分别逐个调用,还要管理该继续还是该中断等等逻辑(这些逻辑是依赖每个Handler返回的标志来决定的)。何不让Handler自己负责把控制向后分发,主控类只需要知道领头的那个Handler最终会把事情处理好就行了。这种结构还有一个好处,就是每个Handler可以自行决定是否该往下传递控制,还可以根据需要替换上下文实例的实现来影响后续的处理。(这一步与上一步是二选一,有些人喜欢在主控类中持有Handler队列,有些人喜欢链式Handler。我个人认为问题不大,两者的实现难度也没有差别,实现需求就行)
最后,我们为了交流方便,把这种组合方式称为“责任链”。
使用状态模式优化if else
参考:http://www.blogjava.net/xzclog/archive/2006/10/16/75399.html