编写业务代码的时候常常会遇到判断,面对各种业务场景,你知道最优方案吗?
让我们看看基本情况:
初级:if else else if一把梭干就完事
中级:switch case、if else、多态、用设计模式包装
高深:清晰所有判断条件的边界,用解释性强且合理的方式
给各位大佬泡上一杯82年的卡布奇诺,细细品味。
代码初窥
需求:判断今日上班情况,当前时间和工作进度作为条件
{
period:afteroon,// 当前时间:afternoon || night
workProgress:start, // 工作进度: start || end
}
if-else
if(period === 'afternoon'){
上班
}else if(period === 'night' && workProgress !== 'end'){
加班
}else {
下班
}
优点: if else 最为常见,是所有程序员最熟悉判断语句,可以包含复杂条件。
缺点: 逻辑过多就会变得非常冗长难以理解。
如果不看上班和加班的表达式能快速理解什么状态对应的下班吗
switch-case
switch(period){
case 'afternoon':
上班
break;
case 'night' && workProgress:
下班
break;
case 'night' && workProgress !== 'end':
加班
break;
default:
肝就完事
break;
}
优点: 多种平行条件下更加简洁直观,可跳出,性能更优。
缺点: 同条件的逻辑过多就会变得像裹脚布,嵌套以及非同条件的表达式难度大。
条件变得复杂,再加一个状态(星期,周二、周四固定加班),还能维护吗
三元运算: 、短路运算 && ||
优点: 代码更加的简洁精炼
缺点: 过于复杂的三元运算语义化不强同时难以维护
period === 'afternoon'? '上班' : (workProgress === 'end'? '下班' : '加班')
同上,条件变得复杂还能维护吗,同时看懂这串代码已经需要一点时间了。。。
策略模式/状态模式 设计模式封装
优点: 易于维护,具有一定解释性,多态
缺点: 代码量复杂度增加,需要一定抽象能力
const AllState = {
'上班':onWork,
'下班':endWork,
'加班':stillWork,
}
const period = 'night';
const workProgress = 'start';
function onWork() {
return period === 'afternoon';
}
function endWork() {
return period === 'night' && workProgress === 'end';
}
function stillWork() {
return period === 'night' && workProgress === 'start';
}
function getWorkState() {
let state = '肝就对了';
Object.keys(AllState).some((result) =>{
if(AllState[result]()){
state = result;
return true;
};
});
console.log(state);
return state;
}
const workState = getWorkState();
增加了代码可维护性和可读性,支持多态,但是也增加了代码量和时间成本
语义化
你是一个新入职的员工,你的老大拍拍你的肩膀告诉你这是前面3个离职员工留下的代码
if(state === 1){
// 一gi窝里giaogiao
}else if(state === 2){
// 左边画个龙右边写个bug
}else if(state === 3){
//do something
}
.....以此类推
新人快速成长秘笈,那就是写没有接口文档,没有需求原型的项目,里面充斥着这样的数字状态的项目
以对象取代判断条件
const stateType = {
start: 1, // 开始
doing: 2, // 进行中
end: 3, // 结束
}
if(state === stateType['start']){
// 一gigiaogiao里giaogiao
}else if(state === stateType['doing']){
// 左边画个龙右边写个bug
}else if(state === stateType['end']){
// do something
}
不要觉得多了一个对象代码就变冗余了,这个对象中的key正是维护这份代码最好的注释
以函数取代判断条件
以一个电商活动节日为例,要求18岁以上,女生优惠比男生优惠力度大
if(sex==='feMale' && age>18) {
charge = (quantity * count) - 800; // 男生优惠800元
}else{
charge = (quantity * count)*0.8 - 500; // 女生8折再优惠500元
}
分解条件的方式改造
1.函数取代判断条件
function allowAge(){
return sex==='feMale' && age>18;
}
2.分解执行函数
function maleCharge(){
return (quantity * count) - 800;
}
function femaleCharge(){
return (quantity * count)*0.8 - 500;
}
3.缩成简单三元
charge = allowAge() ? femaleCharge() : maleCharge();
执行语句都被封装起来且变得简短易懂
骚操作
1.如果有不执行的条件,为了减少不必要的代码提前return
function allowAge(age){
if (age<'18') throw new Error('No adult!');
// 正常
}
2.给参数设置默认值,这样就不需要做undefined类型处理了
function maleCharge(arg){
const count = arg || 5;
return (quantity * count) - 800;
}
// 优化后
function maleCharge(count = 5){
return (quantity * count) - 800;
}
3.将多个简单条件放在数组对象里使用includes
if(fruit === 'apple'||fruit === 'banana'||fruit === 'lemon') eatFruit()
if(['apple','banana','lemon'].includes(fruit)) eatFruits()
4.当状态比较多的时候可以用这种方式来包装
es6中的Map允许使用对象来作为key
const period = 'night';
const workProgress = 'end';
const worklist = () => {
return new Map([
[{period:'morning',workProgress:'start'},()=>{/* 上班 */}],
[{period:'afternoon',workProgress:'end'},()=>{/* 上班 */}],
[{period:'night',workProgress:'doing'},()=>{/* 加班 */}],
[{period:'night',workProgress:'start'},()=>{/* 加班 */}],
[{period:'night',workProgress:'end'},()=>{/* 下班 */}],
//...
])
}
利用对象做为key可以存储多个数据(条件)
function getWorkState (){
const todayWorkState = [...worklist()].filter(([key])=>(key.period === period && key.workProgress === workProgress));
return todayWorkState[0][1]();
}
const workState = getWorkState ();
如果你看完之后满脑子的加班上班,那说明你看懂了!
如果觉得不错,请素质四连,点赞、关注、转发、评论,毕竟要恰饭的嘛