API設(shè)計(jì)原則
一致、易于掌握和強(qiáng)大的API是Qt最著名的優(yōu)點(diǎn)之一。此文總結(jié)了我們?cè)谠O(shè)計(jì)Qt風(fēng)格API的過(guò)程中所積累的訣竅(know-how)。其中許多是通用準(zhǔn)則;而其他的則更偏向于約定,遵循這些約定主要是為了與已有的API保持一致。
雖然這些準(zhǔn)則主要用于對(duì)外的API(public API),但在設(shè)計(jì)對(duì)內(nèi)的API(private API)時(shí)也推薦遵循相同的技巧(techniques),作為開(kāi)發(fā)者之間協(xié)作的禮儀(courtesy)。
如有興趣也可以讀一下Jasmin Blanchette的Little Manual of API Design (PDF)或是本文的前身Matthias Ettrich的Designing Qt-Style C++ APIs。
1. 好API的6個(gè)特質(zhì)
API之于程序員就如同圖形界面之于普通用戶(end-user)。API中的『P』實(shí)際上指的是『程序員』(Programmer),而不是『程序』(Program),強(qiáng)調(diào)的是API是給程序員使用的這一事實(shí)。
在第13期Qt季刊,Matthias的關(guān)于API設(shè)計(jì)的文章中提出了觀點(diǎn):API應(yīng)該極簡(jiǎn)(minimal)且完備(complete)、語(yǔ)義清晰簡(jiǎn)單(have clear and simple semantics)、符合直覺(jué)(be intuitive)、易于記憶(be easy to memorize)和引導(dǎo)API使用者寫(xiě)出可讀代碼(lead to readable code)。
1.1 極簡(jiǎn)
極簡(jiǎn)的API是指每個(gè)class的public成員盡可能少,public的class也盡可能少。這樣的API更易理解、記憶、調(diào)試和變更。
1.2 完備
完備的API是指期望有的功能都包含了。這點(diǎn)會(huì)和保持API極簡(jiǎn)有些沖突。如果一個(gè)成員函數(shù)放在錯(cuò)誤的類(lèi)中,那么這個(gè)函數(shù)的潛在用戶就會(huì)找不到,這也是違反完備性的。
1.3 語(yǔ)義清晰簡(jiǎn)單
就像其他的設(shè)計(jì)一樣,我們應(yīng)該遵守最少意外原則(the principle of least surprise)。好的API應(yīng)該可以讓常見(jiàn)的事完成的更簡(jiǎn)單,并有可以完成不常見(jiàn)的事的可能性,但是卻不會(huì)關(guān)注于那些不常見(jiàn)的事。解決的是具體問(wèn)題;當(dāng)沒(méi)有需求時(shí)不要過(guò)度通用化解決方案。(舉個(gè)例子,在Qt 3中,QMimeSourceFactory不應(yīng)命名成QImageLoader并有不一樣的API。)
1.4 符合直覺(jué)
就像計(jì)算機(jī)里的其他事物一樣,API應(yīng)該符合直覺(jué)。對(duì)于什么是符合直覺(jué)的什么不符合,不同經(jīng)驗(yàn)和背景的人會(huì)有不同的看法。API符合直覺(jué)的測(cè)試方法:經(jīng)驗(yàn)不很豐富的用戶不用閱讀API文檔就能搞懂API,而且程序員不用了解API就能看明白使用API的代碼。
1.5 易于記憶
為使API易于記憶,API的命名約定應(yīng)該具有一致性和精確性。使用易于識(shí)別的模式和概念,并且避免用縮寫(xiě)。
1.6 引導(dǎo)API使用者寫(xiě)出可讀代碼
代碼只寫(xiě)一次,卻要多次的閱讀(還有調(diào)試和修改)。寫(xiě)出可讀性好的代碼有時(shí)候要花費(fèi)更多的時(shí)間,但對(duì)于產(chǎn)品的整個(gè)生命周期來(lái)說(shuō)是節(jié)省了時(shí)間的。
最后,要記住的是,不同的用戶會(huì)使用API的不同部分。盡管簡(jiǎn)單使用單個(gè)Qt類(lèi)的實(shí)例應(yīng)該符合直覺(jué),但如果是要繼承一個(gè)類(lèi),讓用戶事先看好文檔是個(gè)合理的要求。
2. 靜態(tài)多態(tài)
相似的類(lèi)應(yīng)該有相似的API。在繼承(inheritance)合適時(shí)可以用繼承達(dá)到這個(gè)效果,即運(yùn)行時(shí)多態(tài)。然而多態(tài)也發(fā)生在設(shè)計(jì)階段。例如,如果你用QProgressBar替換QSlider,或是用QString替換QByteArray,你會(huì)發(fā)現(xiàn)API的相似性使的替換很容易。這即是所謂的『靜態(tài)多態(tài)』(static polymorphism)。
靜態(tài)多態(tài)也使記憶API和編程模式更加容易。因此,一組相關(guān)的類(lèi)有相似的API有時(shí)候比每個(gè)類(lèi)都有各自的一套API更好。
一般來(lái)說(shuō),在Qt中,如果沒(méi)有足夠的理由要使用繼承,我們更傾向于用靜態(tài)多態(tài)。這樣可以減少Q(mào)tpublic類(lèi)的個(gè)數(shù),也使剛學(xué)習(xí)Qt的用戶在翻看文檔時(shí)更有方向感。
2.1 好的案例
QDialogButtonBox與QMessageBox,在處理按鈕(addButton()、setStandardButtons()等等)上有相似的API,不需要繼承某個(gè)QAbstractButtonBox類(lèi)。
2.2 差的案例
QTcpSocket與QUdpSocket都繼承了QAbstractSocket,這兩個(gè)類(lèi)的交互行為的模式(mode of interaction)非常不同。似乎沒(méi)有什么人以通用和有意義的方式用過(guò)QAbstractSocket指針(或者能以通用和有意義的方式使用QAbstractSocket指針)。
2.3 值得斟酌的案例
QBoxLayout是QHBoxLayout與QVBoxLayout的父類(lèi)。好處:可以在工具欄上使用QBoxLayout,調(diào)用setOrientation()使其變?yōu)樗?垂直。壞處:要多一個(gè)類(lèi),并且有可能導(dǎo)致用戶寫(xiě)出這樣沒(méi)什么意義的代碼,((QBoxLayout *)hbox)->setOrientation(Qt::Vertical)。
-
API
+關(guān)注
關(guān)注
2文章
1624瀏覽量
64081
原文標(biāo)題:API設(shè)計(jì)原則
文章出處:【微信號(hào):C_Expert,微信公眾號(hào):C語(yǔ)言專(zhuān)家集中營(yíng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論