如何优雅的使用 if else

发布时间:2024年01月22日

作为一个程序员在开发中?if else?判断在代码中是必不可少的,但是?if else?判断使用多了嵌套多了不利于代码维护,看起来也头疼难以理解,接下来以为大家介绍一下我是怎么避免过多冗余的?if else?嵌套的。

0. 嵌套的if语句的典型用例

在最终执行有用操作之前,想对一些数据执行各种检查,以确保其有效性。这种情况下,可以使用if语句的嵌套来按顺序执行多个检查,只有当所有检查都通过时才执行有用的操作。这有助于确保数据在被处理之前是安全的。

冗余的写法:

function sendMoney(account, amount) {  
    if (account.balance > amount) {  
        if (amount > 0) {  
            if (account.sender === 'user-token') {  
                account.balance -= amount;  
                console.log('Transfer completed');  
            } else {  
                console.log('Forbidden user');  
            }  
        } else {  
            console.log('Invalid transfer amount');  
        }  
    } else {  
        console.log('Insufficient funds');  
    }  
}

优化后:

function sendMoney(account, amount) {  
    if (account.balance < amount) {  
        console.log('Insufficient funds');  
        return;  
    }  
    if (amount <= 0) {  
        console.log('Invalid transfer amount');  
        return;  
    }  
    if (account.sender !== 'user-token') {  
        console.log('Forbidden user');  
        return;  
    }  
    account.balance -= amount;  
    console.log('Transfer completed');  
}

与嵌套的if语句不同,我们有多个if语句,每个if语句执行检查并在条件不满足时立即返回。在这种模式中,我们可以将每个if语句称为防御式编程(guard clause)。这种方式使代码更易阅读和维护,减少了嵌套深度。

如果有使用 node.js 的童鞋,可能会在Express中间件中看到了这种流程:

function authMiddleware(req, res, next) {  
    const authToken = req.headers.authorization;  
    if (!authToken) {  
        return res.status(401).json({ error: 'Unauthorized' });  
    }  
    if (authToken !== 'secret-token') {  
        return res.status(401).json({ error: 'Invalid token' });  
    }  
    if (req.query.admin === 'true') {  
        req.isAdmin = true;  
    }  
    next();  
}

再看看这样的写法:

function authMiddleware(req, res, next) => {  
    const authToken = req.headers.authorization;  

    if (authToken) {  
        if (authToken === 'secret-token') {  
            if (req.query.admin === 'true') {  
                req.isAdmin = true;  
            }  
            return next();  
        } else {  
            return res.status(401).json({ error: 'Invalid token' });  
        }  
    } else {  
        return res.status(401).json({ error: 'Unauthorized' });  
    }  
};

是不是瞬间感觉这样的代码就比较恶心了,所以我们尽量要避免回调地狱的写法,采用防御式编程的写法,这种模式使代码更加清晰和易于维护。

1. 如何去写防御式编程

0. 找到最内层/成功的 if 语句

在这里,我们可以清楚地看到它是cond3的if语句。在这之后,如果不再进行更多的检查,我们可以执行我们一直想要执行的操作。

function func(cond1, cond2, cond3) {  
    if (cond1) {  
        if (cond2) {  
            if (cond3) {  
                console.log('PASSED!');  
                console.log('taking success action...');  
            } else {  
                console.log('failed condition 3');  
            }  
        } else {  
            console.log('failed condition 2');  
        }  
    } else {  
        console.log('failed condition 1');  
    }  
}

1.将最外层的 if 语句 return

否定?if?条件以将?else?语句的主体放入其中,并在其后添加一个?return?语句。

删除?else?语句的大括号(保留主体,因为它仍然包含以前嵌套的if语句),并将?if?语句的右括号移到?return?语句的后面。

function func(cond1, cond2, cond3) {  
    if (!cond1) { // 👈 反转后的if条件  
        // 👇 以前的else子句的主体 
        console.log('failed condition 1');  

        return; // 👈 失败时退出  
    }  

        // 👇 需要转换的剩余嵌套if语句 
    if (cond2) {  
        if (cond3) {  
            console.log('PASSED!');  
            console.log('taking success action...');  
        } else {  
            console.log('failed condition 3');  
        }  
    } else {  
        console.log('failed condition 2');  
    }  
}

2. 对每个嵌套的if执行相同的操作,直到达到成功的if

function func(cond1, cond2, cond3) {  
    if (!cond1) {  
        console.log('failed condition 1');  
        return;  
    }  
    if (!cond2) {  
        console.log('failed condition 2');  
        return;  
    }  
  
    if (!cond3) {  
        console.log('failed condition 3');  
        return;  
    }
    console.log('PASSED!');  
    console.log('taking success action...');
}

3. 插件提示

VS Code中安装JavaScript Booster扩展后,反转if语句变得非常容易。在这里,我们只需要将光标放在if关键字中,然后激活"显示代码操作"命令(默认情况下是Ctrl + .)。

4. 将代码拆分为多个函数,以始终避免使用else

如果我们在if/else中检查数据后还想执行其他操作怎么办?例如:

function func(cond1, cond2) {  
    if (cond1) {  
        if (cond2) {  
            console.log('PASSED!');  
            console.log('taking success action...');  
        } else {  
            console.log('failed condition 2');  
        }  
        console.log('after cond2 check');  
    } else {  
        console.log('failed condition 1');  
    }  
    console.log('after cond1 check');  
}

在这个函数中,无论cond1的值如何,'after cond1 check'这一行都会打印。如果cond1true,则cond2的值也是类似的情况。

在这种情况下,要使用防御使编程需要更多的工作:

如果我们尝试使用防御使编程,将会重复出现在if/else检查之后的行:

function func(cond1, cond2) {  
    if (!cond1) {  
        console.log('failed condition 1');  
        console.log('after cond1 check');  
        return;  
    }  
  
    if (!cond2) {  
        console.log('failed condition 2');  
        console.log('after cond2 check');  
        console.log('after cond1 check');  
        return;  
    }  
    console.log('PASSED!');  
    console.log('taking success action...');  
    console.log('after cond2 check');  
    console.log('after cond1 check');  
} 
func(true);

由于这些行必须被打印,我们在返回之前在防护子句中打印它们。然后,我们在所有(!)后续的防护子句中再次打印它们。如果所有的防护子句都通过,那么在主函数体中再次打印。

那么,我们该怎么办?如何使用防御式编程并仍然遵守DRY原则?

嗯,我们将逻辑分割成多个函数:

function func(cond1, cond2) {  
    checkCond1(cond1, cond2);  
    console.log('after cond1 check');  
}  
  
function checkCond1(cond1, cond2) {  
    if (!cond1) {  
        console.log('failed condition 1');  
        return;  
    }  
    checkCond2(cond2);  
    console.log('after cond2 check');  
}  
  
function checkCond2(cond2) {  
    if (!cond2) {  
        console.log('failed condition 2');  
        return;  
    }  
    console.log('PASSED!');  
    console.log('taking success action...');  
}

让我们将这个方法应用到之前看到的Express中间件中:

function authMiddleware(req, res, next) {  
    checkAuthValidTokenAdmin(req, res, next);  
}  
  
function checkAuthValidTokenAdmin(req, res, next) {  
    const authToken = req.headers.authorization;  
    if (!authToken) {  
        return res.status(401).json({ error: 'Unauthorized' });  
    }  
    checkValidTokenAdmin(req, res, next);  
}  
function checkValidTokenAdmin(req, res, next) {  
    const authToken = req.headers.authorization;  
    if (authToken !== 'secret-token') {  
        return res.status(401).json({ error: 'Invalid token' });  
    }  
    checkAdmin(req, res, next);  
}  
function checkAdmin(req, res, next) {  
    if (req.query.admin === 'true') {  
        req.isAdmin = true;  
    }  
    next();  
}

在某种程度上,我们用责任链模式替代了if/else语句。当然,对于像基本的Express请求中间件这样的简单逻辑,这可能有些过度,但这里的优点在于它将每个额外的检查委托给一个单独的函数,分离了职责,防止了过多的嵌套。

主要收获 在代码中使用嵌套的if语句可能导致复杂且难以维护的代码。相反,我们可以使用防御式编程使我们的代码更加可读和线性。我们可以将防御式编程应用于不同的情境,并将它们拆分为多个函数,以避免重复和分担职责。通过采用这种模式,我们最终编写更干净和更易维护的代码。

文章来源:https://blog.csdn.net/weixin_42981560/article/details/135756323
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。