浅谈API设计
為什么需要了解一些API設計?
只要你編程,你就是API Designer
一個好的設計,模塊之間的耦合應該也是API級別的
一個程序,如果你獨立開發,那你既是API的Designer,也是API的User
如果你和你的同事一起開發,,你既是你開發的模塊API的Designer,也是其他同事模塊API的User
一個好的API應該具備哪些特點?
1. 易學易用(Easy to learn and use)
要做到易學易用,需要滿足以下基本要求:
a. API命名的要適應用戶的習慣并遵循一些模式。例如:使用類似于add/delete, get/set,push_bach/pop_back這種大家比較熟悉的命名方法。避免用戶使用get獲取一個數據,但是需要使用insert插入數據。
b. API的設計需要盡量簡化用戶的使用復雜度,我們看下STL vector的使用,非常簡潔!
c.盡量提供一些方便用戶的api方法
例如提供一個STL vector提供at方法供用戶獲取指定位置的元素
但同時也提供API供用戶直接獲取第一個和最后一個元素
reference front(); reference back();2. 引導用戶寫出可讀性高的代碼(Leads to readable code)
好的API設計,可以引導用戶寫出高可讀性的代碼,下面這個例子非常生動:
實現 1:
實現 2:
slider = new QSlider(Qt::Vertical); slider->setRange(8, 128); slider->setValue(6); slider->setObjectName("volume");顯然第二種設計更易引導用戶寫出可讀性高的代碼
3. 很難被誤用
一個好的API設計,會使用戶很容易寫出正確的代碼,而不是錯誤的代碼。
這點非常重要,如果你的API很容易用錯,那么,一方面用戶會吐槽,另一方面,API的維護成本也很高
so,當你收到很多錯誤報告的時候,不要抱怨用戶的使用方法有問題,review下自己的API,是不是很容易被誤用
4. 方便擴展(Easy to extend)
api會變的越來越“大”,未來,api會提供新的類,類中會有新的方法,方法會有新的參數,枚舉數據也會有新的枚舉值。
因此,在API設計過程中,需要時刻提醒自己保證API的可擴展性
5. 完整(Complete)
所謂的完整,并不是指API滿足用戶所有的功能需求,而是說,基于這些API,可以滿足所有功能需求。
我們還是拿STL::Vector來做說明,從獲取數據的角度,API提供了reference at (size_type n); 就是完整的,另外提供的front back都是方便用戶獲取數據,用戶完全可以個性化實現這樣的功能。但是,如果只提供了front、back,而沒有提供at這樣的api,就是不完整的
兼容性
在設計API時,非常重要的點是要提前考慮API的發布方式,在發布過程中,兼容性非常重要
我們可以將兼容性分為:源代碼兼容,二進制兼容,功能兼容
在Deliver新版本的API時,需要明確告知用戶,API版本在哪些層面做到了向后兼容
源代碼向后兼容:老的程序,使用新的API庫依然能夠正常工作
二進制向后兼容:直接升級庫文件,老的程序不必重新編譯就能使用新的庫文件
功能兼容向后兼容:老的程序,使用新的API庫,不影響已有功能
功能兼容是業務的范疇,這里不展開。著重討論下源代碼兼容和二兼職兼容。一個很有意思的討論Source compatible vs. Binary compatible
一般來說,二進制兼容是源代碼兼容的子集。如果你的代碼打破了源代碼兼容,基本上可以肯定你也打破了二進制兼容。相反則不成立,一個API是源代碼兼容但不是二進制兼容表示你的代碼無需如何修改,只要重新編譯程序即能正常工作。
我們看下c++來,什么情況下我們會滿足源代碼兼容,但不滿足二進制兼容
c++發布api有靜態和動態庫兩種方式,這兩種發布方式各有優劣,當采取動態庫的發布方式,就面臨二進制兼容問題
c++通過頭文件使用動態庫,編譯時也據此產生二進制代碼,因此,在考慮動態庫兼容性的時候,只要考慮庫使用已有的頭文件是否和新的動態庫兼容
c++使用動態庫最常見的二進制兼容問題就是使用虛函數作為接口產生的。c++虛函數通過虛函數表實現,虛函數表具有以下特點:
1)虛函數按照聲明順序放在表中
2)父類的虛函數放在子類的虛函數之前
so,如果我們在新版本的動態庫中插入新的接口定義,由于虛函數的順序,導致二進制兼容問題
即使你在你的接口中將新增虛函數放在最后,由于接口可能被繼承,而父類的虛函數在子類虛函數之前,因此還是會導致二進制兼容性問題
為了解決這個問題,我們可以采用pimpl來解決!
有一篇非常棒的文章,C++ 工程實踐(5):避免使用虛函數作為庫的接口
一些API開發的建議:
1. 踐行TDD
2. 如果可能,盡早和API使用方溝通
3. 重視命名,它比你想象的更重要
Reference:
Joshua Bloch:How to Design a Good API and Why it matters
Jasmin Blanchette Trolltech :The Little Manual of API Design
Kinds of Compatibility: Source, Binary, and Behavioral
?
總結
- 上一篇: debian 下修改boot停留时间
- 下一篇: java中如何将非整数保留到小数点后指定