继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java编程细节-重构-为什么 if-else 不是好代码

30秒到达战场
关注TA
已关注
手记 286
粉丝 95
获赞 569

平时开发中if-else用的多吗?

其实这是个再正常不过的coding习惯,当我们代码量小的时候用来做条件判断是再简单不过的了。

但对于优秀程序员来说,这并不是好代码,

为啥?

抛开剂量谈毒性都是耍流氓

在使用条件判断语句的地方,如果代码量小,需要判断的场景少的话,

那么没有比 if-else 更合适的语句,比如下面这样

.... if(object.getIndex() > 0) { //do something } else { //do other things }

那在什么情况下 if-else 才会变差呢?

以上面的代码为例子,当需要判断的情况逐渐增加的时候,上面的代码可能会变的难以维护。

在进阶高级开发的路上,应该逐步培养起这种前瞻意识,

即使在代码还在起步阶段,应该要能够看到将来代码发展的趋势,

比如上面的代码,当情况越来越多的时候,if-else可能会发展出许多个分支:

这是完全可能的,以我的经验来说就在不少项目上见过这样的代码。

而且代码执行块中的逻辑可能在几次迭代后变的非常复杂,就像下面这样

看到这段代码第一感觉就是想杀个小伙伴祭天。

如何重构掉这段代码

对于这种代码我们重构的目标可以有两个深度,看自己强迫症的严重程度决定

· 继续用 if-else,只达到剥离执行代码块

· 用工厂模式去耦合

对于这两种其实不是非此即彼的关系,而是优化深度不同。第一种相对比较简单,可以重构成下面这样子

代码清爽了很多,

现在这段代码可以清楚的看出来都处理了哪些情况,条件判断的代码只关注了条件的不同,

而对于不同条件的具体处理逻辑我们剥离到了其他地方,

这样即使写到脑袋迷糊,也不至于说漏了哪个条件没判断。

进一步优化

在上面的优化之后,如何再用工厂模式来继续重构呢?

从上的代码看的出来,不同的条件下,执行的逻辑是不同的,那么可以把这种执行逻辑抽象出来,用多态的概念来定义不同的执行方式。

完成了这一步之后,就可以把代码块中不同条件下的方法抽到各个不同的具体类里面去了,

还可以进一步优化吗?可以的,甚至这里的条件判断都可以不要,我们可以定义一个工厂来把 new ExecutorWithTag()这件事给包了,

对工厂模式还有印象吗,上面这段代码在我之前的工厂模式一文里出现过,这里可以算是工厂模式的一个实际应用。

在经过这一轮重构之后,我们之前在一个类里面写的那堆代码已经抽离到多个不同的类里了,

现在在原来的类里的代码变成怎样了呢,

重构之后各个Executor和主类中的耦合已经降到很低了,

而且代码整洁度提高了很多,之前那个类的一段50+行的代码变成了2行,这就是重构的意义。



作者:Java高级架构
链接:https://www.jianshu.com/p/051aa54671a6
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP

热门评论


if(target.name=='小明') {

 do

 }elseif(target.name=='小花') {

 do

}

解耦后:

public interface class Rule {

  public void func do();

}

public class ARule implements Rule {

  public void func do(Target target) {

  // 把判断隐藏在这里

  if (target.name === '小明') {// do}

  }

}


public class Handler {

 private Rule[] rules;

 public void func add(Rule rule) {

  rules.add(rule);

 }


 public void func do(Target target) {

  for(Rule rule:rules) {

  rule.do(target);

  }

 }

}


public class Fact {

  public Handler func create(Target target) {

  Handler handler = new Handler();

  ARule a = new ARule(); //小花同理

  handler->add(a);

  return handler;

  }

}


Factory facHandler = new Fact();

Handler handler = facHandler.create(target);

handler.do();


执行入口类,依赖一个工厂, 只调用工厂的方法实例化相对应的处理类, 减少了对类的依赖, 职责单一,也满足开闭原则, 代码也没有重复, 整体上来说是挺好的    


再看一下这个factory类,把类的实例化放到一个方法里面,依赖一个target, 根据target的属性来实例化不同的类,当有新的if判断,需要在这个类加入,并且实例化, 对上游类(执行入口类)而言是无感的,体现了高内聚, 但是由于加入新的类,在这个工厂类也需要修改,如果说依赖target的更多属性来判断, 在选择new 一个对象, 这样而言, 不满足开闭原则,但是这对修改而言地方比较小, 也不会影响到第一个版本,优化前的测试单例, 可以满足目前的耦合状况 总结下:高内聚, 高耦合(可能过渡依赖target的属性, 以及对应的if类),职责也不太单一 (主观认为因为用到多个if了)


把多个if,do something的内容封装到类中, 并且抽象了一个process方法作为接口的方法,在do something 来说,隔离了变化,不会改其中一个if类, 而影响到了其他, 而且改其中一个if类,也不会影响上游类(调用if类, 如factory的类), 高内聚,  总结下: 高内聚,职责单一(只做了自己东西, 当然由于系统越负责,做的东西越来越多就不职责单一,也要跟具体业务来判断), 松耦合(有改动时候, 不会影响到其他类, 而且单例测试不需要重写)


总体上,如果熟悉业务, if是没有先后顺序的话,我认为用工厂模式+观察者模式比较好, 把所有判断隐藏在观察者身上, 尽量保证变化不影响其他类,

代码见评论,有好的方法都在评论指导下哈


分析一下:

执行入口类,依赖一个工厂, 只调用工厂的方法实例化相对应的处理类, 减少了对类的依赖, 职责单一,也满足开闭原则, 代码也没有重复, 整体上来说是挺好的

查看全部评论