你是否见过这样的代码?一个函数长达几百行,包含数据验证、数据库查询、业务逻辑处理、文件操作、发送通知……仿佛一个全能的瑞士军刀,什么事情都往里塞。这就是我们要讨论的问题——你的函数为什么要做那么多事?
单一职责原则:代码整洁的基石
在面向对象设计领域,有一个鼎鼎大名的原则叫做「单一职责原则」(Single Responsibility Principle)。它的大意是:每个类、每个函数应该只有一个引起它变化的原因。翻译成大白话就是:一个函数只做一件事,而且把这件事做好。
为什么这很重要?想象一下,如果你家的厨房只有一个多功能电器——它同时是微波炉、烤箱、电饭煲、榨汁机。当榨汁机坏了,你就要整机维修;当你想升级微波炉时,整个电器都得换。这种「紧耦合」的设计会让你的生活一团糟。代码也是如此。
如何判断函数是否做了太多事?
这里有几个简单的判断标准:
- 函数名无法准确描述功能:如果你发现函数名叫
processUserDataAndValidateAndSaveToDbAndSendEmail,那它明显做了太多事。 - 需要用「并且」来描述函数功能:「这个函数用来处理订单并且验证库存并且计算价格并且发送通知……」当你在描述时需要说「并且」,说明该拆分了。
- 超过100行:虽然代码行数不是绝对标准,但如果一个函数超过100行,通常意味着它承担了太多职责。
- 难以测试:如果你发现测试一个函数需要准备十几种不同的场景和数据,说明它的职责过于复杂。
重构实战:一个订单处理函数的蜕变
让我们来看一个实际例子。假设你有一个这样的函数:
function processOrder(order) {
// 验证订单
if (!order.items || order.items.length === 0) {
throw new Error("订单不能为空");
}
// 检查库存
for (const item of order.items) {
const stock = db.query("SELECT stock FROM products WHERE id = ?", item.id);
if (stock < item.quantity) {
throw new Error("库存不足");
}
}
// 计算价格
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
// 应用折扣
if (order.coupon) {
total *= 0.9;
}
// 保存订单
db.execute("INSERT INTO orders ...");
// 发送邮件
emailService.send(order.user.email, "订单确认");
// 记录日志
logger.info("Order processed: " + order.id);
}
这个函数做了多少件事?粗略一数:验证、查库存、计算价格、应用折扣、保存订单、发送邮件、记录日志。足有七件事!
经过单一职责原则重构后:
function processOrder(order) {
validateOrder(order);
checkInventory(order.items);
const total = calculateTotal(order);
saveOrder(order, total);
sendOrderConfirmation(order);
logOrderProcessed(order.id);
}
function validateOrder(order) {
if (!order.items || order.items.length === 0) {
throw new Error("订单不能为空");
}
}
function calculateTotal(order) {
let total = order.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
return order.coupon ? total * 0.9 : total;
}
// ... 其他函数各自负责单一职责
重构后的代码,每个函数都「干净」了:名字清晰、功能单一、易于测试、便于维护。如果将来需要修改折扣逻辑,你只需要动 calculateTotal 函数,完全不用担心会影响库存检查或邮件发送。
写在最后
写代码如同烹饪。最开始,你可能只能做出一道「乱炖」——把所有食材都扔进锅里,虽然能吃,但味道实在不敢恭维。随着经验积累,你会学会把食材分开处理:肉是肉、菜是菜、汤是汤,最后再巧妙地组合在一起。这就是代码的「厨艺」。
下次当你准备在一个函数里添加新功能时,先问问自己:这件事应该由另一个函数来做吗?让你的函数「只做一件事」,你会发现代码变得可读、可维护、可测试,而你自己也会成为更好的程序员。
毕竟,在代码的世界里,「简单」才是真正的「复杂」。
觉得有用就点个赞吧~