1. 背景

if/else是高级编程语言中最基础的功能,虽然 if/else 是必须的,但滥用 if/else,特别是各种大量的if/else嵌套,会对代码的可读性、可维护性造成很大伤害,对于阅读代码的人来说就是一场灾难。

本系列博客的目的不是消除if/else,而是如何“写好”if/else

2. 方法

根据if/else的使用方式和场景,大概有如下解决方法

多态

表驱动

职责链模式

卫语句

Optional

调整判断逻辑,抽取方法,逻辑优化

本篇博客我介绍的是表驱动,后续博客会介绍其他案例

首先来看下最简单的if…else if…场景,也是经常可以在代码中看到的案例

3. 案例

有如下业务代码demo,根据type值,判断然后返回设备的名称

//逻辑表达模式固定的 if…else
public String getDeviceName(int type){
if (type == 1) {
return "ONT";
} else if (type == 2) {
return "OLT";
} else if (type == 3) {
return "ONU";
} else if (type == 4) {
return "MXU";
}
return null;
}

随着时间的积累和项目的迭代,可能会增加越来越多的类型,那么后人会继续增加if/else分支,代码中存在的分支判断就会越来越多,当分支数量实在是多的难以维护的时候,我们就要考虑下,有办法能让这些代码变得更优雅吗?

可能有的人会说用switch/case来重构代码

public String getDeviceName(int type) {
switch (type) {
case 1:
return "ONT";
case 2:
return "OLT";
case 3:
return "ONU";
case 4:
return "MXU";
default:
return null;
}
}

可以看到,换成switch/case也是一样,后续也要维护大量case分支,特别是当同样的逻辑判断出现在多个地方的时候,代码的可读性和维护难易程度将变得非常的糟糕。每次修改时,你必须找到所有有逻辑分支的地方,并修改它们

下面,我就来介绍一种针对这种if/else判断的最简单的重构方式,那就是使用表驱动

4. 表驱动重构代码

表驱动方法(Table-Driven Methods),《代码大全》对此进行了详细地讲解。

表驱动法是一种编程模式(Scheme),从表里面查找信息而不使用逻辑语句(if 和case) 它的好处是消除代码里面到处出现的if、else、switch语句,让凌乱代码变得简明和清晰。

对简单情况而言,表驱动方法可能仅仅使逻辑语句更容易和直白,但随着逻辑的越来越复杂,表驱动法就愈发有吸引力。

static Map<Integer, String> deviceType2NameMap = new HashMap<>();
static {
deviceType2NameMap.put(1, "ONT");
deviceType2NameMap.put(2, "OLT");
deviceType2NameMap.put(3, "ONU");
deviceType2NameMap.put(4, "MXU");
}

static方式可以在类初始化时就加载,当然,如果不想写成static,也可以自行加载

那么,查询的时候,直接get就可以了,而且不需要对key值进行额外的判空

String deviceName = deviceType2NameMap.get(type);

当然,还有一种逻辑固定的if/else也很常见

if ("run".equals(action)) {
doRun(param);
} else if ("fly".equals(action)) {
doFly(param);
} else if ("sleep".equals(action)) {
doSleep(param);
} // ....

这里分支后的执行过程换成了函数,不同的行为执行不同的函数

转换为表驱动方式如下

public class Test {

// 假定上述的param类型为int
Map<String, Consumer<Integer>> actionMappings = new HashMap<>();
initActionMap(){
// 使用方法引用替换Lambda表达式
// Test::doRun等价于param -> doRun(param)
actionMappings.put("run", Test::doRun);
actionMappings.put("fly", Test::doFly);
actionMappings.put("sleep", Test::doSleep);
} doRun(int param) {...}
doFly(int param) {...}
doSleep(int param) {...}
// ....
}

调用方式如下

actionMappings.get("run").accept(param);

可能有人不清楚Consumer是个什么,为什么最后又执行了accept方法

这里简单说下

Consumer<T>是Java8以后提供的函数式接口

T:入参类型;没有出参

调用方法:void accept(T t);

因为没有出参,常用于打印、发送短信等消费动作

由此可见,表驱动的优势

数据逻辑分离,保证在修改数据时,不会对逻辑产生影响。

单元测试时可以注入表格,只要数据可以转换成表,我们可以输入任意形式的数据。

逻辑固定写死在程序中,因为修改逻辑成本高,数据则是灵活变换的,因为修改数据成本低。

保证多人开发时代码的稳健性,简单的逻辑易于读懂易于维护,并且多人使用时,只用修改数据段即可,而数据本身不需要再测试。

来源:华为云社区征文 作者:EmindCC

#华为云·寻找黑马程序员#【代码重构之路】如何“消除”if/else的更多相关文章

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

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

  2. 大型情感剧集Selenium:1_介绍 #华为云·寻找黑马程序员#

    学习selenium能做什么? 很多书籍.文章中是这么定义selenium的: Selenium 是开源的自动化测试工具,它主要是用于Web 应用程序的自动化测试,不只局限于此,同时支持所有基于web ...

  3. python让你再也不为文章配图与素材发愁,让高清图片占满你的硬盘! #华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  4. #华为云·寻找黑马程序员# 如何实现一个优雅的Python的Json序列化库

    在Python的世界里,将一个对象以json格式进行序列化或反序列化一直是一个问题.Python标准库里面提供了json序列化的工具,我们可以简单的用json.dumps来将一个对象序列化.但是这种序 ...

  5. 使用Python开发小说下载器,不再为下载小说而发愁 #华为云·寻找黑马程序员#

    需求分析 免费的小说网比较多,我看的比较多的是笔趣阁.这个网站基本收费的章节刚更新,它就能同步更新,简直不要太叼.既然要批量下载小说,肯定要分析这个网站了- 在搜索栏输入地址后,发送post请求获取数 ...

  6. 爬虫新宠requests_html 带你甄别2019虚假大学 #华为云·寻找黑马程序员#

    python模块学习建议 学习python模块,给大家个我自己不专业的建议: 养成习惯,遇到一个模块,先去github上看看开发者们关于它的说明,而不是直接百度看别人写了什么东西.也许后者可以让你很快 ...

  7. #华为云·寻找黑马程序员#微服务-你真的懂 Yaml 吗?

    在Java 的世界里,配置的事情都交给了 Properties,要追溯起来这个模块还是从古老的JDK1.0 就开始了的. "天哪,这可是20年前的东西了,我居然还在用 Properties. ...

  8. 三伏天里小试牛刀andriod 开发 #华为云·寻找黑马程序员#

    2019年07月,北京,三伏天,好热啊.越热自己还越懒得动换(肉身给的信号),但是做为产品经理/交互设计师的,总想着思考些什么(灵魂上给的信号),或者是学习些什么,更有利于将来的职业发展吧,哈哈哈.工 ...

  9. 使用jieba分析小说太古神王中,男主更爱谁?去文章中找答案吧!#华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

随机推荐

  1. xms跨平台基础框架 - 基于.netcore

    背景 敝人经过多年开发,数百个项目“打磨(折磨)”,各种国内外框架平台都有涉及,没有一款称心顺手的,原因有三,一是设计反人类,二是不开源根本无法突破框架限制,三是即使开源也是阉割版,然后xms就开始萌 ...

  2. Project Euler 56: Powerful digit sum

    一个古戈尔也就是\(10^{100}\)是一个天文数字,一后面跟着一百个零.\(100^{100}\)更是难以想像的大,一后面跟着两百个零.但是尽管这个数字很大,它们各位数字的和却只等于一.考虑两个自 ...

  3. 【Elasticsearch 7 探索之路】(二)文档的 CRUD 和批量操作

    上一篇,我们介绍了什么是 Elasticsearch,它能做什么用以及基本概念(索引 Index.文档 Document.类型 Type)理解.这篇主要对 文档的基本 CRUD 和 倒排索引进行讲解. ...

  4. python——自行实现sorted函数

    仿照内建函数sorted,自行实现一个sort函数,能够为列表进行排序 看下面实例的前提是掌握 0.掌握sorted函数的用法.1.函数基本概念.2.函数是如何传参的.3.掌握三元表达式.4.掌握内建 ...

  5. 易初大数据——2019年10月17日 王庆超 spss

    开放数据库链接是为解决异构数据库间的数据共享而产生, 现已成为WOSA的主要部分和基于windows环境的一种数据库访问接口和标准ODOC为异构数据库访问提供统一接口,允许应用程序以SOL.为数据存取 ...

  6. 品优购(IDEA版)-第二天

    品优购-第2天 学习目标 目标1:运用AngularJS前端框架的常用指令 目标2:完成品牌管理的列表功能 目标3:完成品牌管理的分页列表功能 目标4:完成品牌管理的增加功能 目标5:完成品牌管理的修 ...

  7. 结合参数接收响应转换原理讲解SpringBoot常用注解

    一.常用注解回顾 1.1 @RequestBody与@ResponseBody //注意并不要求@RequestBody与@ResponseBody成对使用. public @ResponseBody ...

  8. 在Debian/Ubuntu上面安装升级nginx到最新版

    在Debian下面通过 apt-get 可以自动安装 nginx,不过版本一般比较老,如果想要使用nginx的最新特性就需要升级版本.   一般安装可以通过编绎源文件安装,但可能需要安装很多编绎工具, ...

  9. C#winfrom文件下载到本地

    string remoteUri = System.IO.Path.GetDirectoryName(url); string fileName = System.IO.Path.GetFileNam ...

  10. Leetcode算法【114. 二叉树展开为链表】

    上周通过一位小伙伴,加入了一个氛围很好的小群,人不多,但是大家保持着对知识的渴望,让我很感动. 我自己也有一个群,人数也不多,但是能真正互动起来一起学习,一起进步的,还是太少.所以,现在也在学习如何让 ...