Spring如何消除代码中的if-else/switch-case

作者:水目沾 时间:2021-12-12 03:04:47 

前言

在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去实现。做的不好的会直接把实现的代码放在 if-else/switch-case 的分支之下:


switch ( type ) {
case case1:
 ...
 ...
 break;
case case2:
 ...
 ...
 break;
case case3:
 ...
 ...
 break
default:
 return null;
}

这样的代码不仅冗长,读起来也非常困难。做的好一点的会把这些逻辑封装成函数然后在分支中调用:


switch ( type ) {
case case1:
 return case1Func();
case case2:
 return case2Func();
case case3:
 return case3Func();
default:
 return null;
}

即使这样也是面向过程思维的写法,以前写 C 程序的时候也总喜欢这样写,毫无设计模式可言。不仅违背开闭原则,而且随着 switch-case 分支的增多,该段代码只会越来越冗长。其实这种代码已经有成熟的模式去消除诸多的 if-else/switch-case 分支。本文就教大家在 Spring 中如何用注解+策略模式+简单工厂的方式消除 if-else/switch-case 。我们就拿 QQ 空间的个人中心举例子,假如 QQ 空间个人中心有四个 tab 分别是列出我的说说、我的日志、我的照片和我的访客。一般的后台代码很有可能如下:


//各个 tab 名称的枚举:
public enum UserRelatedType {
/**
 * 说说
 */
SHUOSHUO("说说"),

/**
 * 日志
 */
RIZHI("日志"),

/**
 * 发布
 */
ZHAOPIAN("照片"),

/**
 * 访客
 */
FANGKE("");

private String desc;

UserRelatedType(String desc) {
 this.desc = desc;
}

public String getDesc() {
 return desc;
}

public void setDesc(String desc) {
 this.desc = desc;
}
}

列出 QQ 用户个人中心相关 tab 的代码:


public List<UserRelatedVO> listRelated(UserRelatedQuery query){

UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) );
switch ( relatedType ) {
 case SHUOSHUO:
  return listRelatedShuoshuo( query );
 case RIZHI:
  return listRelatedRizhi( query );
 case ZHAOPIAN:
  return listRelatedZhaopian( query );
 case FANGKE:
  return listRelatedFangke( query );
 default:
  return null;
}
}

而采用注解+策略模式+简单工厂,重构后代码如下:

1、定义一个注解,用来完全消除 if-else:


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RelatedTypeAnnotation {
/**
 * 用户相关类型名称
 */
UserRelatedType value();
}

2、先定义了个接口,所有 tab 都要实现该接口。其中 list 是 tab 数据展示的方法。


public interface UserRelated {

/**
 * 列出详细信息
 *
 * @param query
 * @return
 */
List<UserRelatedVO> list(UserRelatedQuery query);
}

3、定义具体的各个 tab 的实现,继承 UserRelated 策略接口

我的说说


@Component("userRelatedShuoshuo")
@RelatedTypeAnnotation( value = UserRelatedType.SHUOSHUO )
public class UserRelatedShuoshuo implements UserRelated {
@Override
public List<UserRelatedVO> list(UserRelatedQuery query) {
 System.out.println("我的说说!");
 return list;
}
}

我的日志


@Component("userRelatedRizhi")
@RelatedTypeAnnotation( value = UserRelatedType.RIZHI )
public class UserRelatedRizhi implements UserRelated {
@Override
public List<UserRelatedVO> list(UserRelatedQuery query) {
 System.out.println("我的日志!");
 return list;
}
}

我的照片


@Component("userRelatedZhaopian")
@RelatedTypeAnnotation( value = UserRelatedType.ZHAOPIAN )
public class UserRelatedZhaopian implements UserRelated {
@Override
public List<UserRelatedVO> list(UserRelatedQuery query) {
 System.out.println("我的照片!");
 return list;
}
}

我的访客


@Component("userRelatedFangke")
@RelatedTypeAnnotation( value = UserRelatedType.FANGKE )
public class UserRelatedFangke implements UserRelated {
@Override
public List<UserRelatedVO> list(UserRelatedQuery query) {
 System.out.println("我的访客!");
 return list;
}
}

3、定义一个从 Spring context 获取 bean 的工具类


@Component
public class SpringContextUtil implements ApplicationContextAware {

private ApplicationContext context;

public ApplicationContext getContext() {
 return context;
}

@Override
public void setApplicationContext(ApplicationContext context)throws BeansException {
 this.context = context;
}
}

4、定义一个简单工厂,用来生产各种 tab 对象。


@Component
public class UserRelatedFactory {

@Autowired
SpringContextUtil springContextUtil;

private static Map<UserRelatedType, UserRelated> userRelatedMap = Maps.newConcurrentMap();

//工厂将 Spring 装配的相关的 Bean 用 Map 保存起来
public UserRelatedFactory(){
 Map<String, Object> beanMap = springContextUtil.getContext().getBeansWithAnnotation(RelatedTypeAnnotation.class);

for(Object userRelated : beanMap.values()) {
  RelatedTypeAnnotation annotation = userRelated.getClass().getAnnotation(RelatedTypeAnnotation.class);
  userRelatedMap.put(annotation.value(), (UserRelated)userRelated);
 }
}

public static UserRelated createRelated(UserRelatedType relatedType) {
 return userRelatedMap.get( relatedType );
}
}

5、调用的代码(listRelated 会在 controller 中被调用)。


public List<UserRelatedVO> listRelated(UserRelatedQuery query){

UserRelatedType relatedType = UserRelatedType.valueOf(StringUtils.upperCase(query.getType()) );
UserRelated related = UserRelatedFactory.createRelated( relatedType );
if( related != null ) {
 return related.list( query );
} else {
 return null;
}
}

重构后的代码如果需要再新增一种 tab,比如我的好友,只需要新增一种类型继承 UserRelated 实现其中的 list,并加上相应的注解即可。

其实这是一种通用的解决方案,当你 if-else/switch-case 的分支超过 3 个、且分支代码相似且冗长的情况下就应该考虑这种模式。这种模式写出的代码面向对象、清晰、易扩展还高大上,何乐而不为呀,赶紧试试吧!

来源:https://juejin.im/post/5ca9f113e51d452b5e458ec3

标签:spring,if-else,switch-case
0
投稿

猜你喜欢

  • Java 中String StringBuilder 与 StringBuffer详解及用法实例

    2021-06-17 12:25:32
  • c# 使用Task实现非阻塞式的I/O操作

    2023-07-21 23:27:39
  • Java 8 动态类型语言Lambda表达式实现原理解析

    2023-08-05 09:04:25
  • java9开始——接口中可以定义private私有方法

    2023-03-27 06:53:15
  • SpringBoot整合Security安全框架实现控制权限

    2022-10-03 14:37:15
  • springboot+vue部署按照及运行方法

    2023-07-15 06:16:09
  • java实现学生成绩档案管理系统

    2023-06-29 22:48:43
  • SpringBoot打Jar包在命令行运行流程详解

    2023-11-24 16:53:59
  • Opencv EigenFace人脸识别算法详解

    2023-07-21 19:30:17
  • Android中TextView动态设置缩进距离的方法

    2023-08-07 09:52:00
  • 如何在Android中实现左右滑动的指引效果

    2023-06-23 09:08:47
  • Java技巧函数方法实现二维数组遍历

    2023-09-12 23:25:00
  • java8中:: 用法示例(JDK8双冒号用法)

    2023-11-25 06:21:21
  • C# GDI+实现时钟表盘

    2023-06-20 07:11:32
  • Tomcat 实现WebSocket详细介绍

    2023-08-12 21:22:11
  • java使用dom4j操作xml示例代码

    2022-03-21 18:28:38
  • java并发编程专题(六)----浅析(JUC)Semaphore

    2023-07-27 23:30:28
  • java写的伪微信红包功能示例代码

    2023-07-05 00:24:23
  • Spring boot + mybatis + Vue.js + ElementUI 实现数据的增删改查实例代码(二)

    2022-11-14 18:37:22
  • Java的Struts框架简介与环境配置教程

    2023-10-29 05:23:03
  • asp之家 软件编程 m.aspxhome.com