综合门户网站建设方案,用c语言做公司网站,怎么查看网站的点击率,做视频给网站到流量观点一#xff08;灵剑#xff09;#xff1a; 前期迭代懒得优化#xff0c;来一个需求#xff0c;加一个if#xff0c;久而久之#xff0c;就串成了一座金字塔。 当代码已经复杂到难以维护的程度之后#xff0c;只能狠下心重构优化。那#xff0c;有什么方案可以优雅…观点一灵剑 前期迭代懒得优化来一个需求加一个if久而久之就串成了一座金字塔。 当代码已经复杂到难以维护的程度之后只能狠下心重构优化。那有什么方案可以优雅的优化掉这些多余的if/else?
1. 提前 return
这是判断条件取反的做法代码在逻辑表达上会更清晰看下面代码
if (condition) {// do something
}else{return xxx;
}其实每次看到上面这种代码我都心里抓痒完全可以先判断!condition干掉 else。
if (!condition) {return xxx;}
// do something2. 策略模式
有这么一种场景根据不同的参数走不同的逻辑其实这种场景很常见。最一般的实现
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操作
OptionalUser 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 或者查找表来调用。
其实通常需要优化的都是整体接口抽象而不是单个接口的实现单个接口实现不清晰通常是因为接口实现和需求不同构造成的。