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 == ) {
return "ONT";
} else if (type == ) {
return "OLT";
} else if (type == ) {
return "ONU";
} else if (type == ) {
return "MXU";
}
return null;
}

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

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

 public String getDeviceName(int type) {
switch (type) {
case :
return "ONT";
case :
return "OLT";
case :
return "ONU";
case :
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(, "ONT");
deviceType2NameMap.put(, "OLT");
deviceType2NameMap.put(, "ONU");
deviceType2NameMap.put(, "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

HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

欢迎报名参会

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

  1. 移动端开发语言的未来的猜想#华为云&#183;寻找黑马程序员#【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  2. Python正则表达式,看完这篇文章就够了...#华为云&#183;寻找黑马程序员#【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  3. 华为云&#183;寻找黑马程序员#海量数据的分页怎么破?【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  4. 重磅!华为云社区·CSDN【寻找黑马程序员】有奖征文活动奖项公布!!

    华为云社区·CSDN[寻找黑马程序员]第一期有奖征文活动在大家的鼎力支持下顺利落幕啦,非常感谢大家一直以来的支持~现在小宅就要隆重公布本次活动的奖项了!! 请各位获奖的伙伴在8月18日前私信联系提供联 ...

  5. #华为云·寻找黑马程序员#【代码重构之路】如何“消除”if/else

    1. 背景 if/else是高级编程语言中最基础的功能,虽然 if/else 是必须的,但滥用 if/else,特别是各种大量的if/else嵌套,会对代码的可读性.可维护性造成很大伤害,对于阅读代码 ...

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

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

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

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

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

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

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

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

随机推荐

  1. GoCN每日新闻(2019-11-07)

    GoCN每日新闻(2019-11-07) GoCN每日新闻(2019-11-07) 1. [译] 排序运行时间能否做到 O(n)?让 Go 语言来告诉你 https://mp.weixin.qq.co ...

  2. SpringBoot:缓存注解@Cacheable详解

    1.查看@Cacheable @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @ ...

  3. Java中Set真的是无序的吗?

    我们经常听说List是有序且可重复的,Set是无序且不重复的.这是一个误区,这里所说的顺序有两个概念,一是按照添加的顺序排列,二是按,照自然顺序a-z排列.Set并不是无序的传统所说的Set无序指的是 ...

  4. 代码审计和动态测试——BUUCTF - 高明的黑客

    根据题目提示,访问http://2ea746a2-0ecd-449b-896b-e0fb38956134.node1.buuoj.cn/www.tar.gz下载源码 解压之后发现有3002个php文件 ...

  5. Java String.split()函数分隔回车注意事项

    作者:Sun1956 原文:https://blog.csdn.net/sun1956/article/details/45096117 --------------------- 我们在Java中如 ...

  6. 【Gamma】Scrum Meeting 1

    目录 写在前面 gamma阶段角色更换 进度情况 任务进度表 Gamma阶段燃尽图 遇到的困难 照片 代码Commit记录 后端 前端 写在前面 例会时间:5.25 22:30-23:00 例会地点: ...

  7. 015 vue的项目

    一:搭建项目 1.框架 在原有的基础上 src: 2.index.html <!DOCTYPE html> <html lang="en"> <hea ...

  8. (转) centos7 RPM包之rpm命令

    原文:https://blog.csdn.net/capecape/article/details/78529159 RPM包与源码包的区别1.软件包分类 源码包:C源代码包 rpm包:编译之后的二进 ...

  9. 【iCore4 双核心板_FPGA】实验二十:NIOS II之UART串口通信实验

    实验指导书及源代码下载地址: 链接:https://pan.baidu.com/s/1g_tWYYJxh4EgiGvlfkVu1Q 提取码:dwwa 复制这段内容后打开百度网盘手机App,操作更方便哦 ...

  10. UUIDGenerator

    import java.util.UUID; //下面就是实现为数据库获取一个唯一的主键id的代码 public class UUIDGenerator { public UUIDGenerator( ...