沒(méi)有經(jīng)過(guò)設(shè)計(jì)的代碼,是沒(méi)有靈魂的。
設(shè)計(jì)涵蓋的內(nèi)容很廣坤按,而API設(shè)計(jì)是與日常開(kāi)發(fā)關(guān)系比較緊密的一塊。換句話說(shuō)呀非,掌握了一些核心的設(shè)計(jì)要領(lǐng),對(duì)代碼質(zhì)量提升是立竿見(jiàn)影的。
無(wú)規(guī)矩不成方圓岸裙,API設(shè)計(jì)一樣猖败。最近學(xué)習(xí)了Google工程師總結(jié)的API設(shè)計(jì)原則,看完后降允,腦海中回憶起自己寫(xiě)的代碼恩闻,方法的命名、參數(shù)順序剧董、異常處置幢尚、功能范圍,無(wú)一不被作者所戳中翅楼。我覺(jué)得很有價(jià)值尉剩,所以拿來(lái)與大家一起分享,相信對(duì)你肯定有幫助毅臊。當(dāng)然理茎,作者總結(jié)的比較簡(jiǎn)潔,具體含義褂微,需要大家思考并深入的體會(huì)功蜓,相信經(jīng)過(guò)一番思考以后,定有收獲宠蚂。
由于原文是生肉,為了給部分小伙伴提供一些便利童社,我進(jìn)行了翻譯求厕,翻譯不好的地方還請(qǐng)指正,在此表示感謝扰楼。當(dāng)然有喜歡生肉的同學(xué)呀癣,我也會(huì)在文末評(píng)論處貼上原文地址,請(qǐng)自取弦赖。
以下是正文部分项栏。
API設(shè)計(jì)原則
通用原則
api應(yīng)該只做一件事,并且要做好
- 功能應(yīng)易于解釋
- 如果很難對(duì)一個(gè)功能命名蹬竖,通常是一個(gè)壞兆頭
- 好名稱驅(qū)動(dòng)開(kāi)發(fā)
- 模塊能夠拆分和合并
最小化內(nèi)容訪問(wèn)權(quán)限
- 類和成員變量盡可能私有化
- 公共類不應(yīng)該有公共變量(常量除外)
- 最大化信息隱藏
- 允許模塊能夠獨(dú)立的使用沼沈、理解、構(gòu)建币厕、測(cè)試列另、調(diào)試
名字很重要 -api是一種小語(yǔ)言
- 命名在很大程度上應(yīng)該是不言自明的(避免過(guò)于隱晦的縮寫(xiě))
- 保持一致,同一個(gè)詞應(yīng)該始終代表一個(gè)含義(在整個(gè)api旦装、跨平臺(tái)的api)
- 保持規(guī)律性-力求對(duì)稱
- 代碼應(yīng)該讀起來(lái)像散文页衙,如:
if (car.speed() > 2 * SPEED_LIMIT){
generateAlert("Watch out for cops!);
}
文檔很重要
重用是一種說(shuō)起來(lái)容易做起來(lái)難的事情。要做到這一點(diǎn),需要良好的設(shè)計(jì)和非常好的文檔店乐。即使當(dāng)我們看到良好的設(shè)計(jì)(這仍然是不常見(jiàn)的)時(shí)艰躺,如果沒(méi)有良好的文檔,我們也不會(huì)看到組件被重用眨八。
- D. L. Parnas, _Software Aging.
Proceedings
of 16th International Conference Software
Engineering, 1994
虔誠(chéng)的寫(xiě)文檔
- 為類描滔、接口、方法踪古、參數(shù)含长、異常、構(gòu)造器編寫(xiě)文檔
- 類:實(shí)例代表什么
- 方法:方法與使用者之間的約定伏穆,如先決條件拘泞、后決條件、副作用
- 參數(shù):表示單位枕扫、表單陪腌、所有權(quán)
api設(shè)計(jì)決策要考慮性能影響
- 不好的決策可能會(huì)限制性能,如:
- 類型可變(參考下一條的例子)
- 使用構(gòu)造方法替換工廠
- 使用實(shí)現(xiàn)類型代替接口
- 不要試圖通過(guò)包裝api來(lái)提升性能
- 好的設(shè)計(jì)通常伴隨好的性能
api設(shè)計(jì)決策對(duì)性能的影響是真實(shí)并且持久的
- Component.getSize() 返回 Dimension
- Dimension是可變的
- 每次調(diào)用getSize()將會(huì)分配一個(gè)Dimension
- 導(dǎo)致數(shù)百萬(wàn)不必要的對(duì)象
- 即使在1.2版本中增加新方案烟瞧,老的代碼依舊執(zhí)行很慢
api必須與平臺(tái)和平共存
- 按規(guī)律辦事
- 遵守標(biāo)準(zhǔn)的命名約定
- 避免廢棄的參數(shù)類型和返回類型
- 利用好api的特性
- 泛型诗鸭、枚舉、默認(rèn)參數(shù)参滴、varargs
- 了解并避免api的陷阱
- Finalizers, public static final arrays
類設(shè)計(jì)
減少可變性
- 類應(yīng)該是不可變的强岸,除非有更好的理由
- 優(yōu)點(diǎn):簡(jiǎn)單、線程安全砾赔、可重用
- 缺點(diǎn):每個(gè)值都有單獨(dú)的對(duì)象
- 如果是可變的蝌箍,保持狀態(tài)空間盡可能小和良好的定義
- 明確何時(shí)調(diào)用那個(gè)方法是合法的
Bad: Date, Calendar
Good: TimerTask
子類只出現(xiàn)在有意義的地方
- 子類化意味著可替代性
- 僅當(dāng)is_a關(guān)系才出現(xiàn)子類
- 否則,請(qǐng)使用組合
- 公共類不應(yīng)該僅僅為了容易實(shí)現(xiàn)而子類化其他公共類
Bad: Properties extends Hashtable暴心, Stack extends Vector
Good: Set extends Collection
設(shè)計(jì)和文檔用于繼承妓盲,否則就禁止它
- 繼承違反了封裝原則,子類對(duì)超類的實(shí)現(xiàn)細(xì)節(jié)敏感
- 如果你允許子類化专普,文檔留作自用
- 保守策略:所有的具體類都final化
Bad: Many concrete classes in J2SE libraries
Good: AbstractSet, AbstractMap
方法設(shè)計(jì)
不要讓使用者做任何模塊可以做的事情
- 減少對(duì)樣板代碼的需求
- 通常通過(guò)剪切和粘貼來(lái)完成
- 丑陋悯衬,煩人,容易出錯(cuò)
不要違反最小化原則
- api的用戶不應(yīng)該對(duì)api的行為感到驚訝
- 這值得付出很大的努力檀夹,甚至犧牲一些性能
public class Thread implements Runnable {
// Tests whether current thread has been interrupted.
// Clears the interrupted status of current thread.
public static boolean interrupted();
}
}
快速失敗-當(dāng)發(fā)生錯(cuò)誤時(shí)筋粗,盡可能早的報(bào)錯(cuò)
- 編譯時(shí)最好- 靜態(tài)類型、泛型
- 運(yùn)行時(shí)击胜,首先調(diào)用發(fā)生錯(cuò)誤的方法
- 方法應(yīng)該是原子失敗的
使用適當(dāng)?shù)膮?shù)和返回類型
- 在輸入時(shí)亏狰,優(yōu)先選擇接口類型而不是類
- _提供靈活性、性能
- 使用最具體的輸入?yún)?shù)類型
- 將錯(cuò)誤從運(yùn)行時(shí)移動(dòng)到編譯時(shí)
- 如果存在更好的類型偶摔,不要使用string
- 字符串是笨重的暇唾,容易出錯(cuò)的,而且很慢
- 不要使用浮點(diǎn)數(shù)來(lái)表示貨幣值
- 二進(jìn)制浮點(diǎn)導(dǎo)致不精確的結(jié)果!
- 使用double(64位)而不是float(32位)
- 精度損失是真實(shí)的,性能損失可以忽略不計(jì)
使用一致的參數(shù)排序
- 尤其重要的是策州,如果參數(shù)類型相同
- 如Collections中的方法瘸味,第一個(gè)參數(shù)一般都是被修改或被查詢的。
避免長(zhǎng)的參數(shù)列表
- 三個(gè)或更少的參數(shù)是理想的
- 更多的用戶將不得不參考文檔
- 一長(zhǎng)串類型相同的參數(shù)是有害的
- _程序員誤轉(zhuǎn)了參數(shù)
- 程序仍在編譯够挂、運(yùn)行旁仿,但行為不正常!
- 兩種縮短參數(shù)列表的技術(shù)
- 拆分方法
- 創(chuàng)建助手類來(lái)保存參數(shù)
避免需要異常處理的返回值
- 返回零長(zhǎng)度數(shù)組或空集合,而不是null
Bad:
異常設(shè)計(jì)
支持unchecked異常
?checked-客戶必須采取恢復(fù)措施
?unchecked–編程錯(cuò)誤
?過(guò)度使用checked的異常會(huì)導(dǎo)致樣板
在異常中包含失敗捕獲信息
- 允許診斷和修復(fù)或恢復(fù)
- 對(duì)于未檢查的異常孽糖,消息就足夠了
- 對(duì)于已檢查的異常枯冈,提供訪問(wèn)器