嵌入式C语言中if/else如何优化详解
观点一(灵剑):
前期迭代懒得优化,来一个需求,加一个if,久而久之,就串成了一座金字塔。
当代码已经复杂到难以维护的程度之后,只能狠下心重构优化。那,有什么方案可以优雅的优化掉这些多余的if/else?
1. 提前 return
这是判断条件取反的做法,代码在逻辑表达上会更清晰,看下面代码:
if (condition)
{// do something }
else
{return xxx; }
其实,每次看到上面这种代码,我都心里抓痒,完全可以先判断!condition
,干掉 else。
if (!condition)
{return xxx;} // do something
2. 策略模式
有这么一种场景,根据不同的参数走不同的逻辑,其实这种场景很常见。最一般的实现:
if (strategy.equals("fast"))
{// 快速执行 }
else if (strategy.equals("normal"))
{// 正常执行 }
else if (strategy.equals("smooth"))
{// 平滑执行 }
else if (strategy.equals("slow"))
{// 慢慢执行 }
看上面代码,有4种策略,有两种优化方案。
2.1 多态
interface Strategy
{void run() throws Exception; }class FastStrategy implements Strategy
{@Overridevoid run() throws Exception
{// 快速执行逻辑} }class NormalStrategy implements Strategy
{@Overridevoid run() throws Exception
{// 正常执行逻辑} }class SmoothStrategy implements Strategy
{@Overridevoid run() throws Exception
{// 平滑执行逻辑} }class SlowStrategy implements Strategy
{@Overridevoid run() throws Exception
{// 慢速执行逻辑} }
具体策略对象存放在一个Map中,优化后的实现
Strategy strategy = map.get(param);
strategy.run();
上面这种优化方案有一个弊端,为了能够快速拿到对应的策略实现,需要map对象来保存策略,当添加一个新策略的时候,还需要手动添加到map中,容易被忽略。
2.2 枚举
发现很多同学不知道在枚举中可以定义方法,这里定义一个表示状态的枚举,另外可以实现一个run方法。
public enum Status
{NEW(0)
{@Overridevoid run()
{//do something }},RUNNABLE(1)
{@Overridevoid run()
{//do something }};public int statusCode;abstract void run();Status(int statusCode)
{this.statusCode = statusCode;} }
重新定义策略枚举
public enum Strategy {FAST {@Overridevoid run() {//do something }},NORMAL {@Overridevoid run() {//do something }},SMOOTH {@Overridevoid run() {//do something }},SLOW {@Overridevoid run() {//do something }};abstract void run();
}
通过枚举优化之后的代码如下
Strategy strategy = Strategy.valueOf(param);
strategy.run();
3. 学会使用 Optional
Optional主要用于非空判断,由于是jdk8新特性,所以使用的不是特别多,但是用起来真的爽。
使用之前:
if (user == null)
{//do action 1 }
else
{//do action2 }
如果登录用户为空,执行action1,否则执行action 2,使用Optional优化之后,让非空校验更加优雅,间接的减少if操作
Optional<User> userOptional = Optional.ofNullable(user);
userOptional.map(action1).orElse(action2);
4. 数组小技巧
来自google解释,这是一种编程模式,叫做表驱动法,本质是从表里查询信息来代替逻辑语句,比如有这么一个场景,通过月份来获取当月的天数,仅作为案例演示,数据并不严谨。
一般的实现:
int getDays(int month){if (month == 1) return 31;if (month == 2) return 29;if (month == 3) return 31;if (month == 4) return 30;if (month == 5) return 31;if (month == 6) return 30;if (month == 7) return 31;if (month == 8) return 31;if (month == 9) return 30;if (month == 10) return 31;if (month == 11) return 30;if (month == 12) return 31;
}
优化后的代码
int monthDays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int getDays(int month){return monthDays[--month];
}
结束
if else 作为每种编程语言都不可或缺的条件语句,在编程时会大量的用到。一般建议嵌套不要超过三层,如果一段代码存在过多的if else嵌套,代码的可读性就会急速下降,后期维护难度也大大提高。
观点二(IT技术控):
不要去过度关注 if/else 的层数,而要关注接口语义是否足够清晰;单纯减少if/else的层数,然后拆出一堆do_logic1, do_logic2…这样的接口是毫无帮助的。
任何一个接口的执行过程都可以表示为:输入 + 内部状态 -> 输出这样的形式,我们分以下几种情况来讨论:
输入、内部状态、输出都很简单,但中间逻辑复杂。比如说一个精心优化过的数值计算程序,可能需要根据输入在不同的取值范围采取不同的策略,还有很多逻辑用来处理会引发问题(比如除0)的边界值,这种情况下 if/else 数量多是难以避免的。
根据步骤拆分出一些内部方法有一定帮助,但也不能完全解决问题。
这种情况下最好的做法是写一篇详细的文档,从最原始的数学模型开始,然后表明什么情况下采取什么样的计算策略,策略如何推导,知道得到代码中使用的具体形式,然后给整个方法加上注释附上文档地址,并且在每个分支的地方加上注释指明对应到文档中哪个公式。
这种情况下虽然方法很复杂,但是语义是清晰的,如果不修改实现的话理解语义就行了,如果要修改实现那么需要参考对照文档中的公式。
输入过于复杂,比如输入带有一堆不同的参数,或者有各种奇怪的flag,每个flag有不同作用。
这种情况下首先需要提高接口的抽象层次:如果接口有多个不同作用,需要拆分成不同接口;如果接口内部根据不同参数进不同分支,需要将这些参数和对应分支包在Adapter里,使用参数的地方改写成Adapter的接口,根据传入的Adapter类型不同进入不同的实现;如果接口内部有复杂的参数转换关系,需要改写成查找表。
这种情况下的主要问题是接口本身抽象的有问题,有更清晰的抽象之后,实现也自然没有那么多if/else了。
输出过于复杂,为了省事一个过程计算出了太多东西,又为了性能加了一堆flag控制是否计算之类。这种情况下需要果断将方法拆分成多个不同方法,每个方法只返回自己需要的内容。
如果不同计算之间有共用的内部结果呢?如果这个内部结果计算并不形成瓶颈,只要提取出内部方法然后在不同过程中分别调用即可;如果希望避免重复计算,可以增加一个额外的 cache 对象作为参数,cache内容对用户不透明,用户只保证相同输入使用同一个cache对象即可,在计算中将中间结果保存到cache中,下次计算前先检查有没有已经得到的结果,就可以避免重复计算了。
内部状态过于复杂。首先检查状态设置的是否合理,是不是有一些本来应该作为输入参数的东西被放到了内部状态中(比如用来隐式地在两个不同方法调用之间传递参数)?
其次,这些状态分别控制哪些方面,是否可以分组然后实现到不同的 StateManager里面?
第三,画出状态转移图,尝试将内部状态分成单层分支,然后分别实现到on_xxx_stat e这样的方法里面,然后通过单层的 switch 或者查找表来调用。
其实通常需要优化的都是整体接口抽象,而不是单个接口的实现,单个接口实现不清晰通常是因为接口实现和需求不同构造成的。
相关文章:
嵌入式C语言中if/else如何优化详解
观点一(灵剑): 前期迭代懒得优化,来一个需求,加一个if,久而久之,就串成了一座金字塔。 当代码已经复杂到难以维护的程度之后,只能狠下心重构优化。那,有什么方案可以优雅…...
【LSTM】读取时间序列数据 | 时间序列数据的小批量划分方法
由于序列数据本质上是连续的,因此我们在处理数据时需要解决这个问题。当序列过长而不能被模型一次性全部处理时,我们希望能拆分这样的序列以便模型方便读取。 Q:怎样随机生成一个具有n个时间步的mini batch的特征和标签? A&…...
K8s in Action 阅读笔记——【12】Securing the Kubernetes API server
K8s in Action 阅读笔记——【12】Securing the Kubernetes API server 12.1 Understanding authentication 在上一章中,我们提到API服务器可以配置一个或多个认证插件(授权插件也是同样的情况)。当API服务器接收到一个请求时,它…...
爆肝整理,3个月从功能进阶自动化测试,一跃成测试卷王...
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 首先先了解自动化…...
人生这场概率游戏,怎么玩
只会标准答案,是不可救药的愚蠢 那么为了便于理解,我用一些典型的案例来讲解,什么是概率游戏,以及这个游戏,应该怎么玩。 比如典型的相亲,婚恋。人生大事,用标准答案来说,你的意中人…...
Redis笔记
缓存过期时间很重要!redis是单线程的 对于内存过多的3中方案: 惰性删除: 在定时删除的基础上,对于已经过期了的数据,redis的随机选择算法一直没有选中这个数据,所以导致它就一直没被删除,但是…...
centos 安装supervisor并运行网站
前言 之前一直用宝塔的**进程守护管理器【Supervisor】**来启动一些项目,如ThinkPHP、Hyperf的项目,或laravel的一些命令。如果不用宝塔怎么办呢? 一、简介[supervisor] [Supervisor] 是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支…...
Hadoop面试题十道
问题 1:Hadoop是什么? 答案:Hadoop是一个开源的分布式计算框架,用于处理大规模数据集的存储和处理。它基于Google的MapReduce和Google文件系统(GFS)的思想,旨在解决大数据量的处理和分析问题。…...
使用Docker-Compose对Docker容器集群快速编排
目录 一、Docker-Compose1、Docker-Compose使用场景2、Docker-Compose简介3、Docker-Compose安装部署4、YAML 文件格式及编写注意事项5、Docker Compose配置常用字段6、Docker Compose 常用命令7、Docker Compose 文件结构8、docker Compose撰写nginx 镜像9、docker Compose撰写…...
React-Redux 对Todolist修改
在单独使用redux的时候 需要手动订阅store里面 感觉特别麻烦 不错的是react有一个组件可以帮我们解决这个问题, 那就是react-redux。 react-redux提供了Provider 和 connent给我们使用。 先说一下几个重点知道的知识 Provider 就是用来提供store里面的状态 自动getState()co…...
初识微信小程序
新建小程序 创建一个新的微信小程序项目: 打开微信开发者工具,点击“新建项目”。 在弹出的窗口中,填写小程序的 AppID、项目名称和项目目录等信息。 点击“确定”按钮,等待微信开发者工具自动下载并安装所需的依赖库和框架。 …...
我们该如何入门编程呢
提醒:以下内容仅做参考,可自行发散。在发布作品前,请把不需要的内容删掉。 随着信息技术的快速发展,编程已经成为一个越来越重要的技能。那么,我们该如何入门编程呢?选择编程语言:选择一种编程…...
App 软件开发《判断6》试卷及答案
App 软件开发《判断6》试卷及答案 文章目录 App 软件开发《判断6》试卷及答案判断题(对的打“√”,错的打“”;共0分)1.”ionic resources --icon"命令用于生成适应不同分辨率的App图标所应用的图片。(✔)2&#…...
MVC工作原理
MVC工作原理 有视图的情况 1.客户端(浏览器)发起请求,DispatcherServlet拦截请求。 2.DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据uri去匹配查询能处理的Handler(也就是我们所说的Controller&#x…...
使用 Redis 统计网站 UV 的方法
使用 Redis 统计网站 UV 的方法(概率算法) 文章目录 前言思路HyperLogLog 使用 Redis 命令操作使用 Java 代码操作 HyperLogLog 实现原理及特点使用 Java 实现 HyperLogLog小结 前言 网站 UV 就是指网站的独立用户访问量Unique Visitor,即相同用户的多次访问需要…...
黑客工具软件大全
黑客工具软件大全100套 给大家准备了全套网络安全梓料,有web安全,还有渗透测试等等内容,还包含电子书、面试题、pdf文档、视频以及相关的网络安全笔记 👇👇👇 《黑客&网络安全入门&进阶学习包》 &a…...
uniapp主题切换功能的第二种实现方式(scss变量+require)
在上一篇 “uniapp主题切换功能的第一种实现方式(scss变量vuex)” 中介绍了第一种如何切换主题,但我们总结出一些不好的地方,例如扩展性不强,维护起来也困难等等,那么接下我再给大家介绍另外一种切换主题的…...
# 蓝牙音频相关知识
蓝牙音频相关知识 文章目录 蓝牙音频相关知识1 音频源2 蓝牙音频编解码器3 一些标准4 蓝牙音频其他相关知识4.1 蓝牙版本4.2 ANC(主动降噪)4.3 音响相关参数4.4 音质评价4.5 HI-Fi声音特点4.6 耳机线材4.7 耳机分类4.8 IP防尘防水等级4.9 噪音与量化噪音…...
【AI作画】使用DiffusionBee with stable-diffusion在mac M1平台玩AI作画
DiffusionBee是一个完全免费、离线的工具。它简洁易用,你只需输入一些标签或文本描述,它就能生成艺术图像。 DiffusionBee下载地址 运行DiffusionBee的硬性要求:MacOS系统版本必须在12.3及以上 DBe安装完成后,去C站挑选自己喜欢…...
2 STM32库函数 之 通用同步异步收发器(USART、串口)所有函数的介绍及使用
2 STM32库函数 之 通用同步异步收发器(USART、串口)所有函数的介绍及使用 前言一、USART固件库函数预览二、USART固件库函数具体介绍2.1 库函数 USART_DeInit2.2 库函数 USART_Init2.2.1 USART_InitTypeDef structure2.2.2 USART_InitTypeDef 成员 USART…...
SpringCloudAlibaba整合Sentinel实现流量控制熔断降级
目录 一、概念 二、整合Sentinel控制台 三、Sentinel规则配置 四、@SentinelResource资源保护注解...
CentOS 7安装 Postgre
零、前置条件 系统CentOS 7,并已联网,已安装gcc或者g编译器,GNU make版本3.80或以上,系统有至少一个除root之外的普通用户user gcc安装-参考链接查看make命令的版本——make --version更新make版本-参考链接postgresql的使用一般…...
rpc 异步非阻塞 io 配置 线程池和队列
相关 雪崩 - 如何重试 - sla和重试风暴的双保证_个人渣记录仅为自己搜索用的博客-CSDN博客 接口耗时公式 耗时 cpu时间 io时间 线程池数量 最佳数目 1s / 平均cpu时间 * 内核数. 最大平均cpu时间 接口耗时- all外部io时间. 结合gc , linux本身其他线程, 只会还少点. …...
【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS
JTS Java Topology Suite 几何计算: 1. 前端js就用这个 Turfjs的类库。参考网站: 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库,参考网站: JTS参考网站: 1. https://github.com/locatio…...
从Window中先多瞥几眼
JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…...
【STM32训练—WiFi模块】第二篇、STM32驱动ESP8266WiFi模块获取天气
目录 第一部分、前言 1、获取心知天气API接口 2、硬件准备 第二部分、电脑串口助手调试WIFI模块获取天气 1、ESP8266获取天气的流程 2、具体步骤 第三部分、STM32驱动ESP8266模块获取天气数据 1、天气数据的解析 1.1、什么函数来解析天气数据? 2.1、解析后…...
Maven私服
Maven 私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的远程仓库(中央仓库、其他远程公共仓库)。 建立了 Maven 私服后,当局域网内的用户需要某个构件时,会按照如下顺序进行请求…...
手写RPC总结篇
协议制定:client到server做交互的通信协议,比如request response 网络端点peer 难点1 : Jetty嵌入 ◆jetty Server ◆ServletContextHandler ◆ServletHolder jetty server 起到网络监听的作用ServletContextHandler注册到jetty server中ServletHolde…...
c++11 标准模板(STL)(std::ios_base)成员类型与常量
流打开模式类型 std::ios_base::openmode typedef /*implementation defined*/ openmode; static constexpr openmode app /*implementation defined*/ static constexpr openmode binary /*implementation defined*/ static constexpr openmode in /*implementation defi…...
我用 ChatGPT 写 2023 高考语文作文:全国卷(一)
【2023】新高考|卷 “好的故事,可以帮我们更好地表达和沟通,可以触动心灵、启迪智慧:好的故事以改变一个人的命运,可以展现一个民族的形象故事是有力量的。” 以上材料引发了你怎样的联想和思考?请写一篇文章 要求&…...
网站建设横条/网站页面关键词优化
概述首先同步下项目概况:上篇文章分享了,路由中间件 - Jaeger 链路追踪(理论篇)。这篇文章咱们分享:路由中间件 - Jaeger 链路追踪(实战篇)。说实话,这篇文章确实让大家久等了&#…...
天津seo博客/怎样优化网站排名
在MFC中滑动条(CSliderCtrl)是个常用的控件,用法如下: 1、设置、取得滑动范围: void SetRange( int nMin, int nMax, BOOL bRedraw FALSE ); void GetRange( int& nMin, int& nMax ) const; 2、设置、取得按…...
wordpress广告位插件/肇庆seo排名
在创建SpringBoot项目时,勾选Spring Security依赖,会在Maven中导入Spring Security。org.springframework.boot spring-boot-starter-security这个依赖中有一个登陆拦截器,SpringBoot项目访问任意接口(页面)都跳转到login登录页面这是Spring…...
网站做的好是不是影响就大/免费的网站域名查询
C字符串长度定义规范 (转载请注明来源于金庆的专栏) 因为总是见到C字符串长度相关的错误, 所有定个规范出来, 有利于减少错误. 关键在于C字符串有个结尾0, 处理时需要注意. 定义字符串长度有两种方式, 一种是用字符串的大小, 一种是字符串的长度.字符…...
可以做平面设计兼职的网站/seo权重优化软件
201. 数字范围按位与 给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。 示例 1: 输入:left 5, right 7 输出:4 示例 2…...
报名网站建设公司哪里有/搜索引擎优化论文3000字
OpenCV是用于构建计算机视觉应用程序的一个开源库。本书将全面介绍新发布的OpenCV 4版本所提供的大量新特性和平台改进。 首先,你将了解OpenCV 4的新特性并安装OpenCV 4来构建计算机视觉应用程序。然后,你将探索机器学习的基础知识,学习设计用…...