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


猜你喜欢
- 在看KMP算法时,想要简单的统计一下执行时间和性能。得出的结论是: Java的String的indexOf方法性能最好,其次是KMP算法,其
- 为什么需要将webView放在独立进程webView 加载网页的时候可能占用大量内存,导致应用程序OOM。webView 在访问结束的时候可
- 01-前言:什么是循环依赖?首先,我们先明确下依赖的定义。 如果一个 Bean bar 的属性,引用了容器中的另外一个 Bean foo,那
- 本文实例讲述了C#通过WIN32 API实现嵌入程序窗体的方法,分享给大家供大家参考。具体如下:这是一个不使用COM,而是通过WIN32 A
- 最近有个老项目想逐步将新业务的数据放到新的数据库,以前的业务还得连接以前的数据库,于是需要整合多数据源 。多数据源实际上是继承了Abstra
- 线程中断:void interrupted()方法:中断线程,例如,当线程A运行时,线程B可以调用线程A的interrupted()方法来设
- 市面上有好多的类比ListView刷新数据的开源框架,如:v4包自带的SwipeRefreshLayout ,以及集ListView、Gri
- 其实写到这里,我已经差不多断气了。。。常规套路,这里是前三篇的传送门,需要的同学可以看一下:JAVA写文本编辑器(三) JAVA写文本编辑器
- 在winform程序中给form添加了keyup事件,但是程序却不响应键盘事件,解决办法是重写Form基类的ProcessCmdKey(re
- 创建started service 应用组件(例如Activity)
- 这几天Java项目中需要用到Redis,于是学习了一下使用Jedis来操作Redis服务器的相关知识,下面为具体的配置和代码。1、Maven
- 本文实例为大家分享了Java实现双向链表的具体代码,供大家参考,具体内容如下双向链表与单链表的对比:1、单向链表查找只能是一个方向,双向链表
- 众所周知springboot项目,使用springboot插件打包的话,会打包成一个包含依赖的可执行jar,非常方便。只要有java运行环境
- 1.相关概念Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。建
- 本文实例讲述了Android播放assets文件里视频文件相关问题。分享给大家供大家参考,具体如下:今天做了一个功能,就是播放项目工程里面的
- 本文实例讲述了Android开发中MotionEvent坐标获取方法。分享给大家供大家参考,具体如下:Android MotionEvent
- 在没讲.net如何随机生成汉字之前先给大家讲下汉字编码组成及原理。1、汉字编码原理到底怎么办到随机生成汉字的呢?汉字从哪里来的呢?是不是有个
- 反射允许我们在编译期或运行时获取程序集的元数据,通过反射可以做到:● 创建类型的实例● 触发方法● 获取属性、字段信息● 延迟绑定.....
- 实践过程效果代码public partial class Form1 : Form{ public Form1()
- 计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下三种:源代码 -> 编译器优化的重排 -> 指令并