🎯 什麼情境該想到我

當你「在 C 這種過程式語言裡想解開一個小依賴,但物件導向那一套手法全都用不上」的時候。

書上說得很直白:在過程式語言中解依賴可沒有在物件導向語言中那麼多選擇——「比如你沒法使用封裝全域引用(268 頁)或是子類化並重寫方法(314 頁)。所有這些物件導向的解依賴手法都行不通。」(p.310)雖然還是可以用連接替換(296 頁)或定義補全(266 頁),但「它們對於解開一些小的依賴又顯得有點殺雞用牛刀了」(p.310)。

書中點名的適用語言:「對於支援函式指標的語言,換函式為函式指標手法是一個可選的方案。眾所周知的支援函式指標的語言就屬 C 了。」(p.310)

什麼時候比連接替換更值得選?書上舉的是一個網路應用,包資訊被保存在線上資料庫中:「我們可以使用連接替換(296 頁)來將這些函式連接到新的函式體,但連接替換有時會給建構過程帶來較大麻煩。比如我們可能會需要將問題函式從它所在的庫中分離出來以便替換它們。更重要的是,在產品程式碼中根本沒法使用連接替換所獲得的接縫來調節行為。如果你想要將程式碼納入測試同時又能提供產品實現的靈活性(比如切換你的程式碼所存取的資料庫的類型)的話,換函式為函式指標是個好主意。」(p.311)

⚙️ 怎麼用(步驟)

書中列出的步驟(p.312):

  1. 找到你想要替換的函式的宣告。
  2. 在每個找到的函式之前建立一個同名的函式指標。
  3. 重新命名原函式的宣告,以避免跟剛才宣告的函式指標重名。
  4. 在一個 C 檔案中初始化這些函式指標,將它們指向相應的函式。
  5. 建構,通過建構錯誤來找出原函式的函式體。將它們改為新的函式名。

書中示範的命名慣例是把原函式改名加上一個表示「產品實作」的後綴,讓原本的名字留給函式指標;初始化則放在某個 C 原始檔的環境初始化函式裡,由 main 呼叫。(p.311–312)

做完之後,書上說:有了這個函式指標,測試檔案便可以替換進來,從而達到感知或分離的目的。(p.312)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • ⚠️ 語言限制:僅限支援函式指標的語言,書中明確點名的是 C。(p.310)物件導向語言有更好的選擇,不該退回這一招。
  • 團隊接受度是前提。 書中誠實地寫出爭議:「不同的團隊對函式指標有著不同的看法。有些團隊認為函式指標極度不安全,因為指標的內容可能會被破壞,從而導致被呼叫的是一塊隨機記憶體。而有些團隊則把它當成有用的工具,當然,小心使用是前提。」(p.310)只有站在後者陣營,才適合用這一招來解開「用其他辦法很難或者無法解開的依賴」。
  • 它的好處是編譯期而非連接期。 「它的好處之一便是發生在編譯期(而非連接期),因此對你的建構系統幾乎沒有影響。」(p.312)這是它相對連接替換的主要優勢。
  • Feathers 建議這只是過渡: 「然而,如果你是在 C 裡面運用這項技術的,那麼請考慮轉移到 C++,以便利用 C++ 提供的各種各樣的接縫。在本書寫作時,許多 C 編譯器都提供了編譯開關來允許你進行 C/C++ 混合編譯。利用這個性能你便可以將 C 專案逐步往 C++ 遷移,每次只需對你關心的那些檔案進行解依賴。」(p.312)換句話說,這一招好用,但它同時是「你的語言選擇限制了你」的訊號。

🔗 相關工具