先来一张镇楼图感受一下 if else 的魔法吧。

一、由一个几百行 if 引发的思考

有个场景,50张字典表,须要为其余服务提供一个对立的接口来校验用户输出的字典表 id 是否非法。

校验逻辑曾经很清晰了,依据参数抉择对应的表校验 id 是否存在。

if("table_a".equals(table)) {      // check id    }    if("table_b".equals(table)) {      // check id    }    if("table_c".equals(table)) {      // check id    }...

再加上参数校验,函数调用,@Autowired bean 等等,一坨几百行的代码 ok 了。再新加表再加 if else 就行了,???? 完满。

如此,N 年后另一个可怜的小伙伴就看到这坨货色。

二、KO 这些 if else

回忆下面的场景,实际上就是要依据表名去确定 id 是否存在表中,那么只有将表名与操作对应起来就行了。故而采纳哈希表的模式,将表名与操作对应起来。局部代码如下:

// 用于保留表与 Function 的对应关系  private final Map<String, Function<Object, Object>> actionMappings = new ConcurrentHashMap<>(50); @PostConstruct private void init() {    // map 初始化    actionMappings.put(TableConstants.TABLE_A, (params) -> tableAManager.getById(params));  }/** * 校验逻辑 * *@param table *@param id */ public boolean valid(String table, Long id) {    Object object = actionMappings.get(table).apply(id);    // 不存在则校验失败    return !Objects.isNull(object); }

如此,N 多行 if 被打消了,这种编程形式也叫做表驱动。尽管 if 没有了,然而在初始化 actionMappings 的时候还是很多行反复代码。上面采纳注解形式解决:

/** * 标记此注解的 bean 会退出根底数据校验全局 Function Map * * @author aysaml * @date 2020/5/7 */@Documented@Inherited@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ValidHandler {  TABLE_ENUM value();}

value 是表名枚举,在须要的类下面加上此注解即可。同时定义一个 context 用来专门存储 actionMappings 。

/** * 数据校验上下文对象,用于保留各表的 Function Map * * @author aysaml * @date 2020/5/7 */@Componentpublic class CommonDataValidContext {  private static final Logger LOGGER = LoggerFactory.getLogger(CommonDataValidContext.class);  private final Map<String, Function<Object, Object>> actionMappings = new ConcurrentHashMap<>(50);  /**   * 办法退出 mappings   *   * @param model 表名   * @param action 办法   */  public void putAction(String model, Function<Object, Object> action) {    if (!Objects.isNull(action)) {      actionMappings.put(model, action);      LOGGER.info(          "[{}] add to CommonDataValidContext actionMappings, actionMappings size : {}",          model,          actionMappings.size());    }  }  /**   * 执行办法获取返回后果   *   * @param model   * @param param   * @return   */  public <P, R> R apply(String model, P param) {    if (actionMappings.containsKey(model)) {      return (R) actionMappings.get(model).apply(param);    } else {      LOGGER.error("执行数据校验时model={}不存在!", model);      throw new RuntimeException("根底数据校验时产生谬误:" + model + "表不存在!");    }  }  /**   * 判断 mappings 中是否含有给定 model 的解决办法   *   * @param model   * @return   */  public boolean containsKey(String model) {    return actionMappings.containsKey(model);  }  /**   * 校验执行办法的返回值是否为空   *   * @param model   * @param param   * @param <P>   * @return   */  public <P> boolean validResultIsNull(String model, P param) {    return Objects.isNull(this.apply(model, param));  }}

而后通过监听器的形式,将含有 ValidHandler 注解的办法退出 actionMappings 。

/** * 根底数据校验解决办法监听器 * * @author aysaml * @date 2020/5/7 */@Componentpublic class CommonValidActionListener implements ApplicationListener<ContextRefreshedEvent> {  @Override  public void onApplicationEvent(ContextRefreshedEvent event) {    Map<String, Object> beans =        event.getApplicationContext().getBeansWithAnnotation(ValidHandler.class);    CommonDataValidContext commonDataValidContext =        event.getApplicationContext().getBean(CommonDataValidContext.class);    beans.forEach(        (name, bean) -> {          ValidHandler validHandler = bean.getClass().getAnnotation(ValidHandler.class);          commonDataValidContext.putAction(              validHandler.value().code(),              (param) -> {                try {                  return bean.getClass().getMethod("getById", Long.class).invoke(bean, param);                } catch (Exception e) {                  e.printStackTrace();                }                return null;              });        });  }}

三、更多打消 if else 的办法。

1. 提前return

这样能够使代码在逻辑表白上会更清晰,如下:

if (condition) { // do something} else {  return xxx;}

依照逆向思维来,优化如下:

if (!condition) {  return xxx;} // do something

还有一种常见的傻瓜编程(如有触犯,敬请见谅,对码不对人???? ):

if(a > 0) {      return true;    } else {      return false;    }

话不多说了,间接 return a > 0; 不香吗?

2. 策略模式

简略来说就是依据不同的参数执行不同的业务逻辑。
如下:

if (status == 0) {  // 业务逻辑解决 0} else if (status == 1) {  // 业务逻辑解决 1} else if (status == 2) {  // 业务逻辑解决 2} else if (status == 3) {  // 业务逻辑解决 3}...

优化如下:

  • 多态
interface A {  void run() throws Exception;}class A0 implements A {    @Override    void run() throws Exception {        // 业务逻辑解决 0    }}class A1 implements A {    @Override    void run() throws Exception {        // 业务逻辑解决 1    }}// ...

而后策略对象寄存在一个 Map 中,如下:

A a = map.get(param);a.run();

2.2 枚举

public enum Status {    NEW(0) {      @Override      void run() {        //do something        }    },    RUNNABLE(1) {      @Override       void run() {         //do something        }    };    public int statusCode;    abstract void run();    Status(int statusCode){        this.statusCode = statusCode;    }}

从新定义策略枚举

public enum Aenum {    A_0 {      @Override      void run() {        //do something        }    },    A_1 {      @Override       void run() {         //do something        }    };    //...    abstract void run();}

通过枚举优化之后的代码如下

Aenum a = Aenum.valueOf(param);a.run();

3. Java 8 的 Optional

Optional次要用于非空判断,是 Java 8 提供的新个性。

应用之前:

if (user == null) {    //do action 1} else {    //do action2}

如果登录用户为空,执行action1,否则执行action 2,应用Optional优化之后,让非空校验更加优雅,间接的缩小if操作

Optional<User> userOptional = Optional.ofNullable(user);userOptional.map(action1).orElse(action2);

4. 决策表

就是下面的表驱动编程办法。

欢送拜访集体博客 获取更多常识分享。