1

引言

在某些场景下,我们会有大量的业务分支,比如支付包括支付宝、微信、银联、Applepay、visa等不同分支,数据库连接时包括sqlserver、mysql、oracle等等,这时候用普通的if-else来实现的话,就会有像下面的代码:
image.png

优点:

  1. 首次开发速度快;

缺点:

  1. 很长;
  2. 可读性、可扩展性很差,要增加新的分支时,会导致频繁修改整个业务类;
  3. 如果同时有多个人对这段代码做修改,还会有很多代码冲突需要合并;
  4. 影响后续开发人员的心情;

下面我们将一步步将其进行优化,用优雅的写法来代替冗长的if...else...。

step1. 首先我们希望他看起来不要那么长,并且当修改某一个业务分支时,只需要修改对应的业务类,而不需要频繁对整个客户端的代码进行变动。优化步骤如下:

1. 将各个分支的业务逻辑放到单独的业务处理类当中:
image.png

2. 客户端只负责分支判断,不关心具体的业务逻辑代码:
image.png

优点:

  1. 简化了客户端的代码;
  2. 代码可读性提高了一些;
  3. 业务变动时,只修改对应的业务类,客户端代码不用动;

缺点:

  1. 虽然看上去条理清晰了不少,但是大片的if..else判断还是在客户端中,当有分支有变动时,客户端代码的调整依旧不可避免;
  2. 实例化业务处理类的代码还需要客户端自己来完成;

step2. 我们需要一个单独的类,专门来负责分支判断和业务处理类的实例化,这样,在添加或修改业务时我们就可以针对这个单独的类来修改,避免了客户端代码的频繁变更。

负责分支判断和实例化业务类这些事可以用我们经常提到的一种设计模式:简单工厂来完成。
简单工厂模式UML
简单工厂模式UML

简单工厂模式替换if...else...
1. 先将所有处理类整理出一个公共的方法抽象到一个接口类当中:
image.png

2. 各个具体的业务处理类实现该接口:
image.png
...此处省略其他业务类的代码...

3. 工厂类:
image.png

客户端代码
image.png

优点:

  1. 进一步简化了客户端的代码;
  2. 此时客户端只需给工厂一个code参数,剩下的逻辑判断和实例化都会由工厂处理并返回给客户端;
  3. 如果有业务变更时,客户端代码基本不需要做改动,只针对工厂类和逻辑处理类做调整即可,整个代码的可读性以及扩展性增强了很多。

缺点:

  1. 大片的if...else还是没有被消除,只是隐藏在了工厂类的内部,没有暴露给客户端而已,当我们需要增加或修改新的nodeEvent时,还是得增加或修改分支;

step3. 如果我们把要用到的处理类,提前放到一个配置文件中,当需要使用时,根据类型从配置文件中找到对应的处理类,就可以避免if..else的判断了。

1. 配置文件(用一个hashmap来模拟):
image.png
此时,我们将业务类的类路径和其对应的code放到了配置文件(hashMap)中,当我们需要用到某一个类时,就可以通过反射+类路径去实例化想要的类了。

2. 工厂类:
image.png
其他代码保持不变。

优点:

  1. 干掉了大片的if...else代码,代码变得简洁了不少;
  2. 提高了程序的可扩展性,当我们需要增加新的业务时,只需要修改配置文件,并增加对应的处理类即可。

缺点:

  1. 但是如果每次调用工厂时,都使用反射去是实例化类,在性能上会有损耗(由于反射涉及的类型是动态解析的,因此无法执行某些java虚拟机优化)。

setp4. 工厂+反射+懒加载 优化

工厂类:
image.png

改动不大,做法也很简单:在工厂类中创建一个处理类的缓存(一个map),每次反射实例化之后,将对应的处理类放入缓存当中。获取实例时,先判断缓存中有没有对应的处理类,有的话直接拿来用就ok了。
优点:

  1. 避免了频繁使用反射机制,提升了效率

缺点:

  1. 当有分支变更时,需要修改两个地方,一个是配置文件,一个是具体的处理类。

如果能将修改配置文件这一步操作也省掉,我们的代码会更优雅。
下面我们看一下如何将配置文件也干掉。

step5. 工厂+反射+自定义注解方式

1. 创建一个自定义注解,用来标记handler对应的NodeEventCode
image.png

2. 在具体的处理类上添加自定义注解:
image.png

3. 新增一个register,用来实例化对象和获取注解:
image.png
image.png
image.png

工厂类:
image.png

至此,我们的优化就算完成了。
可以看到,客户端和工厂类只需要简单的几行代码,就可以代替大量的if...else,并且我们的项目结构也更加清晰。
从扩展性上来讲,当需要新增分支时,只需要添加相应的处理类并加上对应的注解即可,无需修改客户端和工厂类,极大的提高了程序的可扩展性。


总结:

1. 功能虽小,如果多思考一下,还是可以有很多能优化的点的;
2. 增强自身水平,可以帮助你考虑的更多;
3. 多阅读他人代码,比如上边的案例,看过spring ioc的可能更容易理解和借鉴;

瓦力
575 声望15 粉丝

一只coder