在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 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;}
}
复制代码

3、定义一个从 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;}
}
复制代码

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

@Component
public class UserRelatedFactory {@AutowiredSpringContextUtil springContextUtil;private static Map<UserRelatedType, UserRelated> userRelatedMap = Maps.newConcurrentMap();//工厂将 Spring 装配的相关的 Bean 用 Map 保存起来@PostConstructpublic void init{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 个、且分支代码相似且冗长的情况下就应该考虑这种模式。这种模式写出的代码面向对象、清晰、易扩展还高大上,何乐而不为呀,赶紧试试吧!记得关注公众号哦,记录着一个 C++ 程序员转 Java 的学习之路。

消除代码中的 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. 消除代码中的 if-else/switch-case的正确姿势

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

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

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

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

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

  8. switch case 穿透

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

  9. JS switch case语句详解

    switch 语句专门用来设计多分支条件结构.与 else/if 多分支结构相比,switch 结构更简洁,执行效率更高.语法格式如下: switch (expr) { case value1 : s ...

  10. 如何优雅的消除代码里的NullPointerException!

    NPE(NullPointerException)是我们代码工作中最常遇到的一个异常,非常的难受,如何优雅的处理它呢. 本篇文章将详细介绍Optional类,以及如何用它消除代码中的null检查.Op ...

最新文章

  1. Cannot resolve method 'getParameter( )'
  2. php中icon,php中iconv函数的使用方法
  3. “黑”掉神经网络:腾讯披露新型AI攻击手法,主流机器学习框架受影响
  4. 2019年第一个工作日!
  5. Linux系统搭建FTP服务器
  6. DCNv2 windows编译 2021ok
  7. Beyond Compare进行内容替换的方法有哪些
  8. parseInt(08)或parseInt(09)转换返回0的解决办法
  9. [转]Oracle DB 管理ASM实例
  10. nginx+PHP+PHP-FPM(FastCGI)在Ubuntu上的安装和配置
  11. php curl ajax get请求,PHP的curl的get,post请求-Fun言
  12. 阿里巴巴开源 Sentinel,进一步完善 Dubbo 生态
  13. 计算机开机引导的结果是,电脑开机显示引导媒体是怎么回事
  14. Ubuntu安装完后设置root密码
  15. AIOps中异常检测的简单应用
  16. 提醒:安装MS11-100 .NET Framework高危漏洞补丁一定要所有服务器一起安装
  17. Python 爬虫常用代码
  18. AD快捷键备份20210202
  19. VirtualBox基础使用教程
  20. Caml 多表关联查询

热门文章

  1. C#设计模式之十八状态模式(State Pattern)【行为型】
  2. C# 判断两个日期是否是同一天
  3. POJ 1221 UNIMODAL PALINDROMIC DECOMPOSITIONS
  4. 数组循环移动 空间复杂度O(1)
  5. 用css实现图片翻转
  6. Java的一个关于“星球”的枚举
  7. 模拟(堆):USACO Jan11 瓶颈
  8. UIImageView三种方式 和 位置分布
  9. 转:KVC与KVO机制
  10. jquery学习笔记一之window.onload与$(document).ready()区别