重构艺术 | 如何优雅地“提炼函数“

在工作中总数遇到非常多的长代码,俗称"屎山",这类代码读起来特别费劲。自己想重构一遍,但是总感觉缺乏经验指导,因此,多读书,读好书可能是最优解之一。读《重构改善即有代码的设计》有感,便写下此篇博客,积累经验!

在软件开发的浩瀚星河中,函数是最基本的代码单元。当我们面对臃肿冗长的函数时,《重构》一书给出的第一剂良方便是"提炼函数"。这个看似简单的重构手法,实则是提升代码质量的关键转折点。

一、重构动机:代码的诗意重构

当函数膨胀到需要滚动三屏才能读完时,它就变成了代码的"黑洞"------既吞噬可读性,又掩盖复用价值。更致命的是,这样的函数往往混杂着多个抽象层级,就像把说明书、操作手册和维修指南揉成一团。提炼函数的本质,是在混沌中建立秩序,让每个函数都成为一首表达清晰意图的代码诗。

二、长度迷思:质量的新度量衡

传统认知中,20行是函数长度的黄金分割点。但Martin Fowler给出了更深刻的见解:函数名称与函数本体之间的语义距离才是核心标准。一个命名精准的函数,即使略长,只要每个代码块都在同一抽象层呼吸,就值得保留。就像好的文学作品,章节长短不重要,重要的是思想的连贯性。

三、重构四部曲

  1. 命名即设计:如同给新生儿取名,新函数的名字要能完整表达其使命。例如"计算税费"比"处理数据"更直指本质
  2. 安全过渡:通过复制粘贴建立新函数的雏形,保留原始函数的执行流程
  3. 参数手术:识别需要传递的局部变量,像外科医生般精确处理;具体情况参考下面的处理方案对照表。
  4. 替换仪式:将原函数中的代码块替换为对新函数的调用,完成重构的最后一舞

参数处理方案对照表

参数类型 特征描述 解决方案 代码示例片段
无参数 被提取代码块不依赖任何外部变量 直接提取为无参数函数 function newFunc() { /* 原代码块 */ }
只读参数 原代码块读取但不会修改外部变量 将变量作为参数传入新函数 function newFunc(readVar) { /* 使用readVar */ }
可修改参数 原代码块会修改外部变量 1. 传入参数并返回修改后的值 2. 直接修改传入的对象属性 function newFunc(input) { return input + 1; } function update(obj) { obj.value++ }
共享参数 原函数和提取函数共同修改同一变量 1. 通过返回值更新变量 2. 使用引用类型参数 3. 封装为对象操作 value = modify(value); modifyInPlace(&value); container.updateValue();
多参数混合 同时包含只读和可修改参数 组合使用上述策略: - 只读参数直接传入 - 可修改参数通过返回值/引用 function calc(readOnly, &output) {return readOnly}

四、复杂场景破局之道

当遇到多返回值困境时,解决方案如月光穿透迷雾:

  1. 构建临时对象封装多个返回值
  2. 改用集合类型(数组/元组)打包数据
  3. 重新审视函数职责,拆分为更细粒度的函数
  4. 在支持语言中利用元组解构等语法糖
javascript 复制代码
// 重构前
function printOwing(invoice) {
  let outstanding = 0;
  console.log("***********************");
  console.log("**** Customer Owes ****");
  console.log("***********************");

  // 计算未结金额
  for (const o of invoice.orders) {
    outstanding += o.amount;
  }

  // 记录到期日
  const today = Clock.today;
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);

  // 打印详情
  console.log(`name: ${invoice.customer}`);
  console.log(`amount: ${outstanding}`);
  console.log(`due: ${invoice.dueDate.toLocaleDateString()}`);
}

// 重构后
function printOwing(invoice) {
  printBanner();
  const outstanding = calculateOutstanding(invoice);
  recordDueDate(invoice);
  printDetails(invoice, outstanding);
}

五、重构哲学:在秩序与混沌之间

提炼函数不是简单的代码搬家,而是一场思维革命。每个提炼动作都应使代码更接近"自解释文档"的理想状态。当函数名能准确传达意图,当参数列表清晰描绘输入输出,当每个函数都保持单一职责,代码就会自然生长出优雅的形态。

重构大师的终极追求,是让代码像散文般流畅,如数学公式般精确。当我们用提炼函数的手法雕刻代码时,其实也在雕刻自己的思维------将混沌的灵感,淬炼成精妙的艺术。

相关推荐
canonical-entropy9 小时前
范式重构:可逆计算如何颠覆DDD的经典模式
低代码·重构·ddd·领域驱动设计·可逆计算·nop平台
unicrom_深圳市由你创科技9 小时前
用 CTE 重构嵌套子查询:让复杂报表 SQL 可读性提升 80%
mysql·重构
Wnq100729 小时前
AI 在法律咨询服务中的革命性变化:技术赋能与生态重构
人工智能·职场和发展·重构·分类·数据分析·全文检索·创业创新
湘-枫叶情缘9 小时前
程序与工业:从附庸到共生,在AI浪潮下的高维重构
人工智能·重构
JZC_xiaozhong9 小时前
异构系统集成提速:重构企业数据流转架构
大数据·重构·架构·数据分析·etl工程师·数据集成与应用集成·异构数据整合
Sheldon一蓑烟雨任平生10 小时前
Vue3 重构待办事项(主要练习组件化)
vue.js·重构·vue3·组件化练习
阿里云云原生11 小时前
云栖实录:重构可观测 - 打造大模型驱动的云监控 2.0 与 AIOps 新范式
阿里云·云原生·重构·云监控·可观测
oioihoii1 天前
跨区域多院区如何破局?浙江三甲医院实现核心医疗系统国产化重构
数据库·重构
TMT星球2 天前
AI重构兴趣内容与营销生态,驱动消费全链路升级
大数据·人工智能·重构
安冬的码畜日常2 天前
【JUnit实战3_14】第八章:mock 对象模拟技术在细粒度测试中的应用(中):为便于模拟重构原逻辑的两种策略
测试工具·junit·重构·单元测试·多态·junit5·mock 模拟