前言
在开发中,发现之前的小伙伴在使用switch case时并不优雅,导致一个switch case的代码块超过了上百行代码,给后来者的维护开发工作带来了极大的困扰。
当我们需要用到switch case作为分支判断时,如果层数是4/5层时其实还好,将代码块抽成方法也比较精简,但是当swicth case的层数越变越多,每增加一个分支都需要在原来的代码块中做修改的话,这并不符合开闭原则,我们就需要一些手段来将其优化了,这里给大家列举两种方式来进行优化。
switch (type){
case 1 -> method1();
case 2 -> method2();
case 3 -> method3();
case 4 -> method4();
case 5 -> method5();
default -> method2();
}
}
两种优化方案
1.基于Map+Function函数式接口
使用Map集合存储类型与方法的对应关系,使用Function函数式接口来简化方法的调用,其中type可以使用枚举类定义,直接上代码:
public class SwitchFactory {
Map<Integer, Function<Object, Object>> map = new HashMap<>();
private static SwitchFactory instance;
// 使用单例模式实例化当前工厂类实例
public static SwitchFactory getInstance() {
if (instance == null) {
synchronized (SwitchFactory.class) {
if (instance == null) {
instance = new SwitchFactory();
}
}
}
return instance;
}
SwitchFactory(){
// 初始化定义
map.put(1, this::function1);
map.put(2, this::function2);
map.put(3, this::function3);
map.put(4, this::function4);
}
// 传入type来获取需要执行的方法,type可以使用枚举类的方式来代替
public Function<Object, Object> getFunction(Integer type){
return map.get(type);
}
private Object function1(Object data) {
return "分支1";
}
private Object function2(Object data) {
return "分支2";
}
private Object function3(Object data) {
return "分支3";
}
private Object function4(Object data) {
return "分支4";
}
}
此时,可以将原本的switch case代码块换成如下代码:
public static void main(String[] args){
SwitchFactory switchFactory = SwitchFactory.getInstance();
// type可用枚举类代替
Integer type=1;
Map data=new HashMap();
// 方法调用
String res =(String) switchFactory.getFunction(type).apply(data);
System.out.println(res);
}
2.基于注解+Enum+策略模式
第一种方案只需要创建一个类,然后增加方法就可以了。当业务逻辑十分相似且较为复杂时,我们可以通过策略模式将 “业务逻辑” 进行抽象, 只用一个注解的形式来实现动态增减分支,而开发人员只需关注具体业务逻辑实现即可。
1、首先定义分支条件type的常量值的枚举类CaseEnum
public enum CaseEnum {
ACCEPT,
READ,
WRITE;
}
2. 定义注解CaseAnnotation,这个注解将用于“方法操作逻辑实现类”之上,标记该类是其中一个分支
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CaseAnnotation {
CaseEnum value();
}
3. 通过策略模式将 “业务逻辑” 进行抽象,定义一个接口,并实现一个分支,其它分支同理
/**
* @Description: 分支统一接口
*/
public interface CaseInterface {
String execute(Map<String,Object> data) throws Exception;
}
/**
* @Description: accept分支逻辑处理
*/
@Component
@CaseAnnotation(value = CaseEnum.ACCEPT)
public class AcceptImpl implements CaseInterface{
@Override
public String execute(Map<String, Object> data) throws Exception {
return "接收逻辑处理";
}
}
4. 在项目启动的过程中,扫描CaseAnnotation注解获取所有分支实现类,通过 Map<String,CaseInterface> 实现枚举值和分支实现类的映射
/**
* @Description: 获取spring应用上下文工具类
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context=context;
}
//获取spring应用上下文(容器)-进而准备获取相应的bean
public ApplicationContext getContext(){
return context;
}
}
/**
* @Description: 实现枚举值和分支实现类的映射
*/
@Component
public class InitCaseBeanMapComponent {
public static Map<CaseEnum,CaseInterface> processMap=new ConcurrentHashMap<>();
@Autowired
private SpringContextUtil springContextUtil;
@PostConstruct
public void init() {
//获取那些带上了注解的 处理实现类
Map<String,Object> map=springContextUtil.getContext().getBeansWithAnnotation(CaseAnnotation.class);
//添加 case常量值~方法操作逻辑实现类 映射
for (Object process:map.values()){
CaseAnnotation annotation=process.getClass().getAnnotation(CaseAnnotation.class);
processMap.put(annotation.value(),(CaseInterface) process);
}
}
public Map<CaseEnum,CaseInterface> getProcessMap(){
return processMap;
}
}
此时,可以将原本的switch case代码块换成如下代码:
Map<String,Object> data = new HashMap<>();
CaseInterface case=InitCaseBeanMapComponent.processMap.get(CaseEnum.ACCEPT);
String res = case.execute(data);
总结
1. 基于Map+Function函数式接口方式,只需要新建一个类,在类中增加分支方法即可,但当业务逻辑较为复杂,类的体积将会变的较大。
2. 基于注解+Enum+策略模式的方式,适合业务逻辑十分相似且较为复杂的场景,可以发现改造过后代码比原本的更多了,但当分支越来越多时,这无疑是值得的