〈C++API設計〉閱讀筆記
最近讀完了 C++ API設計 中文版,覺得裡面有很多觀念很不錯,都是自己缺乏的知識
因此稍微在此把各節大綱做個簡要筆記,留做未來工作上做參考
尤其這本書的目錄含蠻詳細的,光是目錄就能當作一個 Checklist 來使用了
目錄的重點摘要(非書籍目錄,有個人的更改)
1 . 為什麼要使用 API
1-1. 可以有更健壯的程式碼
1-1-1. 隱藏實作細節
1-1-2. 提高程式碼壽命
1-1-3. 促進模組化
1-1-4. 減少重複的程式碼
1-1-5. 移除硬編碼
1-1-6. 易於改變實作
1-1-7. 易於優化
1-2. 可以提高程式碼重用性
1-2-1. 更一般性的介面
1-2-2. 對於功能需求更深刻的了解
1-2-3. 顧及開發人員與客戶的共同利益
1-2-4. 全球化以及現代化的互相協作
1-3. 對平行開發可以更友善
1-3-1. 簡化關聯開發工作
1-3-2. 提供簡單實作以便編譯與連結
1-3-3. 提早撰寫單元測試
1-3-4. 獨立工作並減少冗餘溝通
2. API 的基本品質
2-1. 問題領域塑模
2-1-1. 良好的抽象概念
1. 高層次概念的明確表達 ( ex: UML )
2. 不公開底層的實作
3. 操作是有意義的( 對非技術人員是顯而易見的 )
4. 類別反映了名稱及其方法
2-1-2. 塑模關鍵物件 Object modeling
1. 定義主要物件的集合
2. 提供所需的操作
3. 界定物件彼此的關係
【 2-2. 隱藏實作細節 information hiding 】
2-2-1. 物理隱藏:宣告與定義
2-2-1-1. 宣告 declaration 引入名稱和型別給編譯器,沒有分配記憶體
extern int i
class MyClass
2-2-1-2. 定義 definition 提供型別結構的詳細資訊為變數分配記憶體
int i = 0 ;
void MyFunc(int value)
{
...
}
2-2-1-3. 一般來說在 .h 宣告,在 .cpp 定義
2-2-1-4. 在 .h 宣告且定義,會公開實作細節,是種不好的作法
2-2-2. 邏輯隱藏:封裝 Encapsulation
2-2-2-1. 封裝的目的是限制其他物件存取權限
2-2-2-2. 封裝是將 API 公共介面和底層實作分開的過程
2-2-2-3. 若沒有好的封裝,高昂代價的重構(refactoring)將無可避免
2-2-2-4. 透過程式語言存取的特性,將 API 資訊隱藏到最高
2-2-3. 隱藏成員變數
2-2-3-1. 封裝也可以是一種方法將資料操作方法的綁定
2-2-3-2. 良好的 API 永遠不公開成員變數
2-2-3-3. 資料成員成為 API 邏輯介面的話,應設定 getter / setter 間接存取
getter / setter 進行間接存取的好處:
1 . 驗證 :對輸入輸出參數進行驗證再進行操作
2 . 延遲運算 :對成本高昂的運算做條件控制,不到非不得已不執行 ( lazy evaluation )
3 . 快取 :儲存需要經常使用的值,被要求時直接返值 ( caching )
4 . 額外的運算 :當被嘗試存取特定變數時,順便進行其他操作
例如 (a) 留下存取紀錄 (b) 修改對應檔案
5 . 通知 :某些物件可能需要監聽某個變數是否被改變,
例如 (a) 控制變數( ex: progress bar) (b) 發出修改通知
6 . 除錯 :可能想要增加日誌( log )語句,或是增加 Assert 語句來執行一些假設
7 . 同步 :每當有值被存取時加入互斥鎖定(mutex locking)
8-1. 更細的存取控制 1 :讓成員變數變 public ,讓使用者可以寫入,唯一理由只有效能
例如:對大量物件執行一個效能緊迫的迴圈(直接存取 public 比 getter / setter 快 2-3 倍)
8-2. 更細的存取控制 2 :不提供 setter 使得參數為 read-only
9 . 維持不變的關係 :將內部資料值進行彼此依賴
2-2-3-4. 資料成員應該總是被宣告為 private 而非 public 或 protected
2-2-3-5. 試著將 public 成員變數以 inline getter / setter 重寫並計時,看是否值得 public
2-2-4. 隱藏實作方法
2-2-4-1. 應該將類別穩定的介面和內部設計的實作分離
2-2-4-2. 切勿返回 private 成員變數的非 const 指標和參考,會破壞封裝
2-2-4-3. 採用 pimpl 慣用法,將實作細節完全隱藏
2-2-4-4. 如果不採用 pipml ,則可在 cpp 檔案中宣告 private 函式為 static ,而在表頭宣告為 private