在工作中總數遇到非常多的長代碼,俗稱“屎山”,這類代碼讀起來特別費勁。自己想重構一遍,但是總感覺缺乏經驗指導,因此,多讀書,讀好書可能是最優解之一。讀《重構改善即有代碼的設計》有感,便寫下此篇博客,積累經驗!
在軟件開發的浩瀚星河中,函數是最基本的代碼單元。當我們面對臃腫冗長的函數時,《重構》一書給出的第一劑良方便是"提煉函數"。這個看似簡單的重構手法,實則是提升代碼質量的關鍵轉折點。
一、重構動機:代碼的詩意重構
當函數膨脹到需要滾動三屏才能讀完時,它就變成了代碼的"黑洞"——既吞噬可讀性,又掩蓋復用價值。更致命的是,這樣的函數往往混雜著多個抽象層級,就像把說明書、操作手冊和維修指南揉成一團。提煉函數的本質,是在混沌中建立秩序,讓每個函數都成為一首表達清晰意圖的代碼詩。
二、長度迷思:質量的新度量衡
傳統認知中,20行是函數長度的黃金分割點。但Martin Fowler給出了更深刻的見解:函數名稱與函數本體之間的語義距離才是核心標準。一個命名精準的函數,即使略長,只要每個代碼塊都在同一抽象層呼吸,就值得保留。就像好的文學作品,章節長短不重要,重要的是思想的連貫性。
三、重構四部曲
- 命名即設計:如同給新生兒取名,新函數的名字要能完整表達其使命。例如"計算稅費"比"處理數據"更直指本質
- 安全過渡:通過復制粘貼建立新函數的雛形,保留原始函數的執行流程
- 參數手術:識別需要傳遞的局部變量,像外科醫生般精確處理;具體情況參考下面的處理方案對照表。
- 替換儀式:將原函數中的代碼塊替換為對新函數的調用,完成重構的最后一舞
參數處理方案對照表
參數類型 | 特征描述 | 解決方案 | 代碼示例片段 |
---|---|---|---|
無參數 | 被提取代碼塊不依賴任何外部變量 | 直接提取為無參數函數 | 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} |
四、復雜場景破局之道
當遇到多返回值困境時,解決方案如月光穿透迷霧:
- 構建臨時對象封裝多個返回值
- 改用集合類型(數組/元組)打包數據
- 重新審視函數職責,拆分為更細粒度的函數
- 在支持語言中利用元組解構等語法糖
// 重構前
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);
}
五、重構哲學:在秩序與混沌之間
提煉函數不是簡單的代碼搬家,而是一場思維革命。每個提煉動作都應使代碼更接近"自解釋文檔"的理想狀態。當函數名能準確傳達意圖,當參數列表清晰描繪輸入輸出,當每個函數都保持單一職責,代碼就會自然生長出優雅的形態。
重構大師的終極追求,是讓代碼像散文般流暢,如數學公式般精確。當我們用提煉函數的手法雕刻代碼時,其實也在雕刻自己的思維——將混沌的靈感,淬煉成精妙的藝術。