我们在写一段复杂的条件判断的时候if,switch算是常用手段了。随着逻辑的复杂,如果if嵌套5层,相信代码的可读性已经是比较差了,需要在整个方法上加注解来说明为什么这么写,这已经不是一个人容易摸索出来的情况了。
我们想象一下如何继续在这样的代码上继续迭代,首先得写好自己的新增逻辑,然后再控制器的类上加上if判定。如果一直新增,或者条件修改,那么控制类一定要跟着变。这样的情况明显是违背开闭原则的。增加或者修改都得修改控制类。
改良1 配置文件
造成上面必须修改控制类的一个重要原因是if这样的逻辑是硬编码到代码的。这样的过程其实是可以抽取成为配置文件的。
文件的修改是方便的,起码是不用再次编译代码了。已经达到一定程度的对扩展开放了,例如过滤器。
但是这种情况一般是对外提供的服务使用的方式,如果是一个项目,这个真没有硬编码来的实在,ide有扫描类的功能,可以发现哪些类没有被使用,写配置文件的方式就很容易忽略掉配置这个步骤。
改良2 再次抽象
我们写的if else代码。其实每次都要写实现过程以及如果判断能这么实现的方式或者标志。
以简单工厂模式为例,如果我们想实现一个创建操作实体类的工厂,我们的代码基本是下面这么写的
public static Operation createOperation(String demo) {
switch (demo) {
case "A":
operationObj = A();
break;
case "B":
operationObj = B();
break;
}
return operationObj;
}
我们使用的是java编码,我们可以利用java的特性来缩减上面的过程
Class.forName(demo).newInstance()
这里使用了java的一个特性,就是通过class对象创建实例,我们是如何省去选择语句的逻辑的呢?
靠约束。这里定义了类名必须是和传入参数一样的名字。如果说if else是线性查找,及他是一个一个从开头一直找到合适的。那么上面的方式,我们采取的就是散列的模式,直接定位。
对比
我们通过上面的两个案例,来对比一下(下面称线性模式,散列模式)。线性模式的特点是可读性强,都有明确的判定,这个到底是什么情况进入。散列模式因为加了抽象,作为了更通用的模式,他阅读起来相对不友好,需要很多注释和约束来控制,否则就会出现大家看着逻辑莫名其妙的情况。散列模式定位更快,线性模式随着判断阅读会越来慢,可能if判定了20次都没到具体的判断上。散列模式如何描述规范是个很大的问题,尤其是规范可能是不好描述的。举个例子,我们真实的场景不单单是创建个对象,可能if判断是创建什么对象,调用什么方法。这个才是我们真是需要的。我们举的例子明显不满足这种情况。
下面就说一种最佳实践
当注解遇到spring
java中的注解,我们在spring中用的特别多,但是自定义注解的情况,相对用的少。下面就通过自定义注解,达到解耦的目的。
首先构建自己的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Executor {
int exec();
}
把注解加入到具体的逻辑代码中
public interface Handler {
@Executor(exec= 1)
public void showInfo();
}
具体的实现类就通过spring注解,让spring扫描到。
最后我们要做的就是维护判定关系。
@Component
public class Processor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<? extends Object> clazz = bean.getClass();
//获取方法上的注解维护一个结构
...
}
}
这里利用了spring构建类的功能,并且可以拿到对应的类,从中获取到方法的注解。自己组织一个map用来保存。
总结
从上面的逻辑上,我们可以看出,我们思维上判定的逻辑一个没少,通过解耦只是做到了扩展的时候写更少的代码,记住,是扩展的时候。有些情况扩展需要不大,if else大可以舒舒服服的用,这个需要开发者对业务有个比较好的把握。