简单3步,优化一下代码中的大量的if-elseif-else语句

200 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情


策略模式说白了就是简单的匹配

Map<Integer,doAction> map = new HashMap<>();

map.put(1, doAction1());
map.put(2, doAction2());
map.put(3, doAction3());

根据不同的参数,从map中取出对应的数据然后进行相应的操作

doAction1() = map.get(1);

你传个1参数,那这个时候执行的不就是 doAction1() 方法吗


上面其实就是策略模式最简单的实现想法

  1. 用 Lambda 的形式写个策略模式
public class Test {

    private static Map<String, Consumer<String>> FUNC_MAP = new HashMap<>();
    private static String MAN = "man";
    private static String WOMAN = "woman";

    static {
        FUNC_MAP.put(MAN, person -> {
            System.out.println(person + "男");
        });
        FUNC_MAP.put(WOMAN, person -> {
            System.out.println(person + "女");
        });
    }

    public static void main(String[] args) {
        Person person = new Person();
        person.setGender(MAN);
        person.setName("张三");
        FUNC_MAP.get(person.getGender()).accept(person.getName());
    }

}

@Data
class Person {
    private String gender;
    private String name;
}
  1. 简单3步,使用 Spring 中 @Autowired 和 @Component 注解实现一个 策略+工厂模式

先看下对外调用的接口(controller)


@Resource
private QueryUserFactory queryUserFactory;

@GetMapping(value = "/queryUser")
public User queryUser(int type, Long userId) {
    QueryUserHandler handler = queryUserFactory.getHandlerMap(type);
    return handler.queryUserById(userId);
}

  • 第一步:先新建个 handler 接口类

这是个接口类,不需要任何注解

package com.example.demo.strategy;

import com.example.demo.User;

public interface QueryUserHandler {

    /**
     * 查询用户信息
     *
     * @param id 用户id
     * @return 用户信息
     */
    User queryUserById(Long id);

}

  • 第二步:实现对应的接口类
package com.example.demo.strategy.impl;

import com.example.demo.User;
import com.example.demo.strategy.QueryUserHandler;
import org.springframework.stereotype.Component;

@Component
public class AppUserImpl implements QueryUserHandler {
    @Override
    public User queryUserById(Long id) {
        return null;
    }
}
package com.example.demo.strategy.impl;

import com.example.demo.User;
import com.example.demo.strategy.QueryUserHandler;
import org.springframework.stereotype.Component;

@Component
public class PcUserImpl implements QueryUserHandler {
    @Override
    public User queryUserById(Long id) {
        return null;
    }
}
  • 第三步:再建个 factory 工厂类

这个类上需要加上 @Component 注解,map 变量上要加上 @Autowired 注解

package com.example.demo.strategy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class QueryUserFactory {

    @Autowired
    private Map<String, QueryUserHandler> handlerMap;

    public QueryUserHandler getHandlerMap(int type) {
        return handlerMap.get(type);
    }
}

这里 @Autowired 注解,会把所有实现 QueryUserHandler 接口的类,全部自动注入到这个map中,比如上面两个实现 QueryUserHandler 接口的类

如果不指定 bean name,Spring 默认生成的 bean name 就是类名,开头字母小写的

如果你打断点看 map 内容的话,应该是有两条数据

key: appUserImpl  value: AppUserImpl.class
key: pcUserImpl   value: PcUserImpl.class

但是这个 getHandlerMap() 方法就有问题了,key 是 string 类型,传进来个 int 类型的怎么能行呢

这个简单啊,让前端改成传 string 类型的不就行了吗

72cdb762cb0921e664ddda04805869a6.gif

或者你自己再写个 int 转 string 的方法

public class TypeToAlias {

    private static final Map<Integer, String> ALIAS_MAP;

    static {
        ALIAS_MAP = Maps.newHashMap();
        ALIAS_MAP.put(1, "appUserImpl");
        ALIAS_MAP.put(2, "pcUserImpl");
    }

    public static String of(int type) {
        return ALIAS_MAP.get(type);
    }

}

然后改下 getHandlerMap 方法

public QueryUserHandler getHandlerMap(int type) {
    String beanName = TypeToAlias.of(type);
    return handlerMap.get(beanName);
}

这不就ok了

简单吧,这不比 if...else 逼格高多了

image.png

image.png