首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C 語言面向物件風格重構實戰:從 Martin Fowler 經典模式到嵌入式工程落地

     編輯:C++ 入門

重構不改變外部行為,透過微小步驟持續改善程式碼結構,提升可讀性、擴充性與維護性。Martin Fowler《重構》雖以 Java 為例,但其核心模式 (提煉函式、封裝變數、移動特性等) 完全語言無關。本文結合嵌入式/底層 C 語言開發實戰,分享關鍵重構手法。

一、函式層級重構:讓 C 函式「說人話」

1. 重新命名:名稱即文件

C 語言傳統偏好縮寫 (`rd_data`, `proc_tx`),但簡潔 ≠ 含糊。建立團隊命名公約:

  • 動詞前綴:`read_`、`write_`、`calc_`、`validate_`、`handle_`
  • 名詞具體化:`read_sensor_temp()` 優於 `rd_tmp()`
  • 布林函式用 `is_`/`has_`/`can_` 開頭:`is_buffer_full()`

好名稱讓呼叫處如閱讀註解,大幅降低認知負荷。

2. 提煉函式:將巨石函式拆解為「意圖清單」

超過 50 行、需上下翻頁的函式必須拆分。提煉準則:

  • 單一職責:每個函式只做一件事
  • 層次一致:高層函式讀起來像業務流程描述
  • 復用機會:提煉出的小函式常被多處呼叫

內聯函式 (`static inline`) 消除呼叫開銷,嵌入式環境無效能顧慮。

3. 提煉判斷條件:告別「與非門」地獄

複雜條件 `if ((a > 0 && b < 10) || (c != NULL && c->flag == 0xFF))` 應提煉為:

static inline bool is_valid_threshold(int a, int b) { return a > 0 && b < 10; }
static inline bool is_flag_cleared(const struct_t* c) { return c && c->flag == 0xFF; }

if (is_valid_threshold(a, b) || is_flag_cleared(c)) { ... }

條件語意瞬間清晰,除錯時可直接對提煉函式下斷點。

4. 簡化函式參數:結構體封裝參數群

參數超過 4 個即屬「壞味道」。解法:

// 重構前
void uart_send(uint8_t port, uint32_t baud, uint8_t parity, uint8_t stop_bits, const uint8_t* data, size_t len);

// 重構後
typedef struct { uint8_t port; uint32_t baud; uint8_t parity; uint8_t stop_bits; } uart_cfg_t;
void uart_send(const uart_cfg_t* cfg, const uint8_t* data, size_t len);

// 配合建構輔助函式
static inline uart_cfg_t uart_cfg_default(void) { return (uart_cfg_t){.port=1, .baud=115200, ...}; }

呼叫端僅需關注變動參數,預設值由輔助函式提供。

二、架構層級重構:馴服 C 語言的全域混亂

1. 解除全域變數噩夢:封裝存取入口

全域變數被任意修改是除錯地獄。三步走封裝:

  1. `static` 限制檔案作用域:`static uint32_t g_sys_tick = 0;`
  2. 提供存取函式:`uint32_t sys_tick_get(void) { return g_sys_tick; }`
  3. 必要時加入斷點/日誌/鎖:除錯時在 `sys_tick_set()` 打條件斷點,瞬間定位修改源頭。

多執行緒/行程環境下,用巨集包裝存取點並印出檔案/函式/行號,同樣有效。

2. 避免函式傳遞隱形 Bug:強制函式宣告

C 語言允許隱式函式宣告 (預設回傳 `int`),導致指標/結構體參數截斷卻能編譯通過、執行時崩潰。鐵律:

  • 所有外部函式必須在標頭檔宣告
  • 啟用編譯器警告 `-Wimplicit-function-declaration -Wstrict-prototypes` 視為錯誤
  • 嚴禁跨檔案直接 `extern` 變數,改用存取函式

3. 調整函式位置:模組化檔案組織

臨時新增的函式隨意放置會破壞模組邊界。重構節點:

  • 功能完成後,將函式移至對應 `.c` 檔
  • 標頭檔僅公開介面,內部函式 `static` 隱藏
  • 建立 `module_private.h` 供單元測試存取內部函式 (僅測試編譯包含)

三、重構融入日常:最高境界是「手中無重構,心中有重構」

許多重構手法 (好名稱、小函式、封裝全域) 在初次編寫時即可落地。養成習慣:

  • 寫測試先行 (TDD) 天然驅動良好結構
  • Code Review 時以「能否一眼看懂意圖」為標準
  • 定期靜態分析 (Cppcheck, MISRA C) 捕捉壞味道

C 語言雖無類別、繼承、多態,但模組化、封裝、單一職責、依賴倒置等設計原則同樣適用。重構不改變語言,改變的是我們駕馭複雜度的能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved