下面我們來(lái)討論一下有關(guān)方法設(shè)計(jì)的幾個(gè)方面,下面說(shuō)的幾個(gè)要點(diǎn)大多數(shù)都是應(yīng)用在構(gòu)造函數(shù)中,當(dāng)然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。 

Item 23:檢查參數(shù)的有效性

非公有的方法我們應(yīng)該用斷言的方法來(lái)檢查它的參數(shù),而不是使用通常大家所熟悉的檢查語(yǔ)句來(lái)檢測(cè)。如果我們使用的開(kāi)發(fā)平臺(tái)是JDK1.4或者更高級(jí)的平臺(tái),我們可以使用assert結(jié)構(gòu);否則我們應(yīng)該使用一種臨時(shí)的斷言機(jī)制。

有些參數(shù)在使用過(guò)程中是先保存起來(lái),然后在使用的時(shí)候再進(jìn)行調(diào)用,構(gòu)造函數(shù)正是這種類型的一種體現(xiàn),所以我們通常對(duì)構(gòu)造函數(shù)參數(shù)的有效性檢查是非常仔細(xì)的。

Item 24:需要時(shí)使用保護(hù)性拷貝

眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區(qū)溢出,數(shù)組越界,非法指針等等,我們的JAVA都有一個(gè)很完善的機(jī)制來(lái)進(jìn)行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語(yǔ)言,如果不采取措施,還是無(wú)法使自己與其他類隔開(kāi)。假設(shè)類的客戶會(huì)盡一切手段來(lái)破壞這個(gè)類的約束條件,在這樣的前提下,你必須從保護(hù)性的方面來(lái)考慮設(shè)計(jì)程序。通過(guò)大量的程序代碼研究我們得出這樣的結(jié)論:對(duì)于構(gòu)造性函數(shù)的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝是必要的。需要注意的是,保護(hù)性拷貝是在檢查參數(shù)的有效性之前 進(jìn)行的,并且有效性檢查是針對(duì)拷貝之后的對(duì)象,而不是原始的對(duì)象。對(duì)于“參數(shù)類型可以被不可信方子類化”的情況,不要用clone方法來(lái)進(jìn)行參數(shù)的保護(hù)性拷貝。

對(duì)于參數(shù)的保護(hù)性拷貝并不僅僅在于非可變類,當(dāng)我們編寫一個(gè)函數(shù)或者一個(gè)構(gòu)造函數(shù)的時(shí)候,如果它要接受客戶提供的對(duì)象,允許該對(duì)象進(jìn)入到內(nèi)部數(shù)據(jù)結(jié)構(gòu)中,則有必要考慮一下,客戶提供的對(duì)象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內(nèi),如果不是,則要對(duì)對(duì)象進(jìn)行保護(hù)性拷貝,并且讓拷貝之后的對(duì)象而不是原始對(duì)象進(jìn)入到數(shù)據(jù)結(jié)構(gòu)中去。當(dāng)然最好的解決方法是使用非可變的對(duì)象作為你的對(duì)象內(nèi)部足見(jiàn),這樣你就可以不必關(guān)心保護(hù)性拷貝問(wèn)題了。):

Item 25:謹(jǐn)慎使用設(shè)計(jì)方法的原型

(1)謹(jǐn)慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風(fēng)格相一致,最后當(dāng)然要注意取一個(gè)大眾所認(rèn)可的名字。

(2)不要追求提供便利的方法:每一個(gè)方法都應(yīng)該提供其應(yīng)具備的功能點(diǎn),對(duì)于接口和類來(lái)方法不要過(guò)多,否則會(huì)對(duì)學(xué)習(xí)使用維護(hù)等等方面帶來(lái)許多不必要的麻煩,對(duì)于每一個(gè)類型所支持的每一個(gè)動(dòng)作,都提供一個(gè)功能完全的方法,只有一個(gè)方法過(guò)于頻繁的使用時(shí),才考慮為它提供一個(gè)快捷方法。

(3)避免過(guò)長(zhǎng)的參數(shù)列表:通常在實(shí)踐中,我們以三個(gè)參數(shù)作為最大值,參數(shù)越少越好,類型相同的長(zhǎng)參數(shù)列尤其影響客戶的使用,兩個(gè)方法可以避免過(guò)長(zhǎng)的參數(shù)這樣的情況發(fā)生,一是把一個(gè)方法分解成多個(gè),每一個(gè)方法只要求使用這些參數(shù)的一個(gè)子集;二是創(chuàng)建輔助類,用來(lái)保存參數(shù)的聚集,這些輔助類的狀態(tài)通常是靜態(tài)的。

對(duì)于參數(shù)類型,優(yōu)先使用接口而不是類。

這樣做的目的是避免影響效能的拷貝操作。

謹(jǐn)慎的使用函數(shù)對(duì)象。

創(chuàng)建函數(shù)對(duì)象最容易的方法莫過(guò)于使用匿名類,但是那樣會(huì)帶來(lái)語(yǔ)法上混亂,并且與內(nèi)聯(lián)的控制結(jié)構(gòu)相比,這樣也會(huì)導(dǎo)致功能上的局限性。 

Item 26:謹(jǐn)慎的使用重載

到底是什么造成了重載機(jī)制的混淆算法,這是個(gè)爭(zhēng)論的話題,一個(gè)安全而保守的方法是,永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)數(shù)目的重載方法。而對(duì)于構(gòu)造函數(shù)來(lái)說(shuō),一個(gè)類的多個(gè)構(gòu)造函數(shù)總是重載的,在某些情況下,我們可以選擇靜態(tài)工廠,但是對(duì)于構(gòu)造函數(shù)來(lái)說(shuō)這樣做并不總是切合實(shí)際的。

當(dāng)涉及到構(gòu)造函數(shù)時(shí),遵循這條建議也許是不可能的,但我們應(yīng)該極力避免下面的情形:

同一組參數(shù)只需要經(jīng)過(guò)類型的轉(zhuǎn)換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點(diǎn):當(dāng)傳遞同樣的參數(shù)時(shí),所有的重載方法行為一致。如果不能做到這一點(diǎn),程序員就不能有效的使用方法或者構(gòu)造函數(shù)。 

Item 27:返回零長(zhǎng)度的數(shù)組而不是null

因?yàn)檫@樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來(lái)處理null返回值。沒(méi)有理由從一個(gè)取數(shù)組值的方法中返回null,而不是返回一個(gè)零長(zhǎng)度數(shù)組。

Item 28:為所有導(dǎo)出的API元素編寫文檔注釋

不愛(ài)寫注釋可能是大多數(shù)程序員新手的通?。òㄅ脊),但是如果想要一個(gè)API真正可用,就必須寫一個(gè)文檔來(lái)說(shuō)明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語(yǔ)言環(huán)境提供了javadoc工具,從而使這個(gè)煩瑣的過(guò)程變得容易,這個(gè)工具可以根據(jù)源代碼自動(dòng)產(chǎn)生API文檔。

為了正確得編寫API文檔,我們必須每一個(gè)被導(dǎo)出的類,接口,構(gòu)造函數(shù),方法和域聲明之前加一個(gè)文檔注釋。

每一個(gè)方法的文檔注釋應(yīng)該見(jiàn)解的描述它和客戶之間的約定。