我想谈一谈这个话题是因为我的上一篇博客在 ITEye 上有一些朋友回复,说 if-else 过多的分支可以使用 switch 或者责任链模式等等方式来优化。确实,这是一个小问题,不过我们还是可以整理一下这个小问题的重构方式。
为什么要优化?
你没有看错。这是要放在第一条谈论的。
有许多人会说,叠起来一堆 if-else 分支,代码就不优雅了。可是,怎样去定义 “优雅” 的概念呢?再退一步说,即便不 “优雅”,又有什么问题?
对于这样一段再普通不过的代码:
int code; if("Name".equals(str)) code = 0; else if("Age".equals(str)) code = 1; else if("Address".equals(str)) code = 2; ...
可以有好多种重构方式,但是使用这样的代码,虽然简陋,但在大多数情况下,并不会影响什么,比如,对可维护性没有影响。当然,如果你发现其中确有不好的一面,那就要考虑重构它。换言之,通常你首先要说出某段代码的问题(比如,你觉得这段代码不符合开闭原则,因为你希望保持这段代码闭合稳定),那么才去存在重构的必要,而不要总是使用 “优雅” 和 “简洁” 搪塞疑问。几乎所有的书上都说要写出优雅的、简洁的代码,这本身无可厚非,但是事物需要使用自己的判断,可不要被习惯性地洗了脑。
在我前一家公司,是典型的通讯和传统软件的公司,代码质量普遍不错,但是很多时候,会看到许许多多不够优雅的代码——也许你觉得不够简洁、美观,但是下代码严谨、清晰,我觉得这就很好。反之,某一些精巧的设计,可能会带来可阅读性和可理解性下降的问题。
寻找代替分支判断的方式
接下去我们再来考虑怎么样去重构优化过多的 if-else 分支。
程序逻辑最基本的组成就是分支、判断和循环。而过多 if-else 正是由于在某一个变化的点上,有许多判断条件和结果分支造成的。所以最基本的解决办法就是把多个判断条件合成一个,也就是把若干个分支合成一个。
但是在大多数情况下,条件判断的分支都是无法合并的。所以,我们需要把这个变化点通过别的途径封装起来,而不是采用 if-else。
1. 用一个 Map 可以做到,if-else 的变化点使用 Map 的 get 方法来代替:
Map typeCodeMap = new HashMap(); typeCodeMap.put("Name", 0); typeCodeMap.put("Age", 1); typeCodeMap.put("Address", 2); ... int code = typeCode.get(type);
2. 枚举:
public enum Codes { Name(0), Age(1), Address(2); public int code; Codes(int code){ this.code = code; } } //使用: int code = Codes.valueOf(str).code;
3. 多态:
ICode iCode = (ICode)Class.forName("com.xxx." + str).newInstance(); int code = iCode.getCode();
当然,如果仅考虑从 String 转向 int 这样的转换,用这样的方式来简化分支判断逻辑,这个方式、这个例子不是很恰当。当然,这样的方式经常被用来做从字符串到具体对象的转换。
还有一些朋友说的这个模式那个模式来解决多 if-else 的问题,这些都是正确的,当然本质上也无一例外基于多态来实现的,所以我就不提及了。这些都不错,至少比那些老说用 switch 来代替 if-else 的有价值多了 :)
最后,对于如此小的一个问题,我要补充说明的一点是,看不得大片 if-else 和看不得大片 new 关键字一样,我觉得这是许多 Java 程序员的既有观念或者说习惯,甚至通病——这并不好。Java 最有价值的地方不是它的语义语法也不是它的虚拟机跨平台和有多高性能,而在于它的社区它的无比丰富的类库,在于使用它的人可以从设计上和宏观上去思考问题。但是 Java 程序员,也包括我在内,很容易把这条路走得过于极端,比如遍地的 Factory,比如漫山遍野的配置,比如永远也不会被复用的可复用代码,比如永远也不会被扩展的可扩展代码,还比如从前到后由内到外的分层,一层又一层。相对于这些方面无止境的追求,我们还是专注于要解决的问题,多写一些清晰可用的代码吧。
文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》
不咋的
没意义. 反而会让人难以维护. 没什么比直接用 if else 的意思更明确. 你按照自己的思维用了这个模式那个模式. 到时代码转手再转手, 根本没人敢动.
最后的问题你也说到了。追求所谓的高可用性, 伸缩性, 拓展性, 到底是为了什么? 故意为了让别人看不懂? 还是刻意追求高大上?
很多什么模式用起来根本就是不实际的,不是为了解决实际问题而用, 根本就是为了使用模式而使用模式.
电子流、问题单 胶片 公司?