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

switch ( type ) {case case1:......break;case case2:......break;case case3:......breakdefault: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 {@Overridepublic List<UserRelatedVO> list(UserRelatedQuery query) {System.out.println("我的说说!");return list;}
}
  • 我的日志
@Component("userRelatedRizhi")
@RelatedTypeAnnotation( value = UserRelatedType.RIZHI )
public class UserRelatedRizhi implements UserRelated {@Overridepublic List<UserRelatedVO> list(UserRelatedQuery query) {System.out.println("我的日志!");return list;}
}
  • 我的照片
@Component("userRelatedZhaopian")
@RelatedTypeAnnotation( value = UserRelatedType.ZHAOPIAN )
public class UserRelatedZhaopian implements UserRelated {@Overridepublic List<UserRelatedVO> list(UserRelatedQuery query) {System.out.println("我的照片!");return list;}
}
  • 我的访客
@Component("userRelatedFangke")
@RelatedTypeAnnotation( value = UserRelatedType.FANGKE )
public class UserRelatedFangke implements UserRelated {@Overridepublic List<UserRelatedVO> list(UserRelatedQuery query) {System.out.println("我的访客!");return list;}
}
  • 定义注解,用来识别身份。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RelatedTypeAnnotation {/*** 用户相关类型名称*/UserRelatedType value();
}
  • 定义一个从 Spring context 获取 bean 的工具类
@Component
public class SpringContextUtil implements ApplicationContextAware {private ApplicationContext context;public ApplicationContext getContext() {return context;}@Overridepublic void setApplicationContext(ApplicationContext context)throws BeansException {this.context = context;}
}
  • 定义一个简单工厂,用来生产各种 tab 对象。
@Component
public class UserRelatedFactory {@AutowiredSpringContextUtil 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 );}
}
  • 调用的代码(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

消除代码中的 if-else/switch-case的正确姿势相关推荐

  1. 如何正确的使用Java8中的Optional类来消除代码中的null检查

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:一书生VOID lw900925.github.io/jav ...

  2. 消除代码中的坏味道,编写高质量代码

    消除代码中的坏味道,编写高质量代码 Intro 想要写出较好的代码,保证代码的高质量需要时刻警惕代码中的坏味道,今天分享一下,我觉得平时写的代码中可能会出现的坏味道代码的一些示例 常见的坏味道代码 B ...

  3. 使用Optional类来消除代码中的null检查

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 作者丨一书生VOID lw900925.github ...

  4. 使用Java8中的Optional类来消除代码中的null检查

      作者:一书生VOID lw900925.github.io/java/java8-optional.html Optional类是Java 8新增的一个类,用以解决程序中常见的NullPointe ...

  5. c语言中continue在case中,C語言switch case 語句中能否使用continue 關鍵字?

    在C語言的學習中,我學習到switch case語句,我發現不能使用continue關鍵字. 代碼如下: #include int main() { int a; printf("input ...

  6. MATLAB Simulink中自定义函数和switch case的用法

    文章目录 1 Simulink自定义函数MATLAB Function 2 Simulink中Switch Case模块的用法 1 Simulink自定义函数MATLAB Function 首先写一个 ...

  7. #华为云·寻找黑马程序员#【代码重构之路】使用Pattern的正确姿势

    1.问题 在浏览项目时,发现一段使用正则表达式的代码 这段代码,在循环里执行了Pattern.matches()方法进行正则匹配判断. 查看matches方法的源码,可以看到 每调用一次matches ...

  8. python3字节转化字符_浅谈 Python3 中对二进制数据 XOR 编码的正确姿势

    Python3 中的默认编码是 UTF-8,这给大家写 Python 代码带来了很大的便利,不用再像 Python2.x 那样为数据编码操碎了心.但是,由于全面转向 UTF-8 编码,Python3 ...

  9. switch case 穿透

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 switch case 穿透 前言 一.什么是switch case 穿透? 二.展示 1.代码示例 前言 什么是switch cas ...

最新文章

  1. mysql桥梁表_以JDBC为桥梁入门MySQL数据库基础
  2. x^A=B(mod C)的解 (离散对数与原根)
  3. 计算机基础- -操作系统环境
  4. 格子里输出 java_蓝桥杯-格子中输出-java
  5. CListCtrl行高问题最终解决方法
  6. 支持向量机(SVM)非线性数据切割
  7. 人列计算机 (节选自《三体》作者:刘慈欣)
  8. 偏向锁java_Java偏向锁
  9. 人工智能:卷积神经网络及YOLO算法 入门详解与综述(二)
  10. 李开复:几年内电子商务上市潮会来临
  11. 计算机本地网络给手机使用吗,电脑共享网络给手机用的方法步骤
  12. 22KDD : COSTA Covariance-Preserving Feature Augmentation for Graph Contrastive Learning
  13. python使用微信设置-用Python来可视化微信好友
  14. iOS 14.4 和 Xcode 12.4 解决的问题
  15. 元宇宙区块链游戏开发 元宇宙手机游戏开发
  16. 什么邮箱最安全?教你三招快速提升邮箱安全性方法,职场人必看!
  17. EPR与自由基捕获实验
  18. 操作系统银行家算法python简单模拟
  19. C Primer Plus 中关于*修饰符(抑制赋值)的一些总结
  20. CiteSpace学习笔记(三)——数据预处理

热门文章

  1. GDUT - 专题学习1 I - 滑动窗口
  2. 有关3DES、DUKPT和MK/SK学习记录
  3. 数字信号处理(七)FIR数字滤波器的设计
  4. 农村经济与科技杂志农村经济与科技杂志社农村经济与科技编辑部2022年第9期目录
  5. 基于逃逸鸟搜索算法的函数寻优算法
  6. 70道Dubbo面试题及答案(最新整理)
  7. JAVA在线教育视频点播学习系统毕业设计 开题报告
  8. 你现在无法访问 blog.csdn.net,因为网站使用的是 hsts。网络错误和攻击通常是暂时
  9. QNX Neutrino 进程间通信编程之Signals
  10. canvas实现聚光灯效果(js)