下面我們來討論一下有關方法設計的幾個方面,下面說的幾個要點大多數都是應用在構造函數中,當然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。
Item 23:檢查參數的有效性
非公有的方法我們應該用斷言的方法來檢查它的參數,而不是使用通常大家所熟悉的檢查語句來檢測。如果我們使用的開發平臺是JDK1.4或者更高級的平臺,我們可以使用assert結構;否則我們應該使用一種臨時的斷言機制。
有些參數在使用過程中是先保存起來,然后在使用的時候再進行調用,構造函數正是這種類型的一種體現,所以我們通常對構造函數參數的有效性檢查是非常仔細的。
Item 24:需要時使用保護性拷貝
眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區溢出,數組越界,非法指針等等,我們的JAVA都有一個很完善的機制來進行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語言,如果不采取措施,還是無法使自己與其他類隔開。假設類的客戶會盡一切手段來破壞這個類的約束條件,在這樣的前提下,你必須從保護性的方面來考慮設計程序。通過大量的程序代碼研究我們得出這樣的結論:對于構造性函數的每個可變參數進行保護性拷貝是必要的。需要注意的是,保護性拷貝是在檢查參數的有效性之前 進行的,并且有效性檢查是針對拷貝之后的對象,而不是原始的對象。對于“參數類型可以被不可信方子類化”的情況,不要用clone方法來進行參數的保護性拷貝。
對于參數的保護性拷貝并不僅僅在于非可變類,當我們編寫一個函數或者一個構造函數的時候,如果它要接受客戶提供的對象,允許該對象進入到內部數據結構中,則有必要考慮一下,客戶提供的對象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內,如果不是,則要對對象進行保護性拷貝,并且讓拷貝之后的對象而不是原始對象進入到數據結構中去。當然最好的解決方法是使用非可變的對象作為你的對象內部足見,這樣你就可以不必關心保護性拷貝問題了。):
Item 25:謹慎使用設計方法的原型
(1)謹慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風格相一致,最后當然要注意取一個大眾所認可的名字。
(2)不要追求提供便利的方法:每一個方法都應該提供其應具備的功能點,對于接口和類來方法不要過多,否則會對學習使用維護等等方面帶來許多不必要的麻煩,對于每一個類型所支持的每一個動作,都提供一個功能完全的方法,只有一個方法過于頻繁的使用時,才考慮為它提供一個快捷方法。
(3)避免過長的參數列表:通常在實踐中,我們以三個參數作為最大值,參數越少越好,類型相同的長參數列尤其影響客戶的使用,兩個方法可以避免過長的參數這樣的情況發生,一是把一個方法分解成多個,每一個方法只要求使用這些參數的一個子集;二是創建輔助類,用來保存參數的聚集,這些輔助類的狀態通常是靜態的。
對于參數類型,優先使用接口而不是類。
這樣做的目的是避免影響效能的拷貝操作。
謹慎的使用函數對象。
創建函數對象最容易的方法莫過于使用匿名類,但是那樣會帶來語法上混亂,并且與內聯的控制結構相比,這樣也會導致功能上的局限性。
Item 26:謹慎的使用重載
到底是什么造成了重載機制的混淆算法,這是個爭論的話題,一個安全而保守的方法是,永遠不要導出兩個具有相同參數數目的重載方法。而對于構造函數來說,一個類的多個構造函數總是重載的,在某些情況下,我們可以選擇靜態工廠,但是對于構造函數來說這樣做并不總是切合實際的。
當涉及到構造函數時,遵循這條建議也許是不可能的,但我們應該極力避免下面的情形:
同一組參數只需要經過類型的轉換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點:當傳遞同樣的參數時,所有的重載方法行為一致。如果不能做到這一點,程序員就不能有效的使用方法或者構造函數。
Item 27:返回零長度的數組而不是null
因為這樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來處理null返回值。沒有理由從一個取數組值的方法中返回null,而不是返回一個零長度數組。
Item 28:為所有導出的API元素編寫文檔注釋
不愛寫注釋可能是大多數程序員新手的通病(包括偶哈~),但是如果想要一個API真正可用,就必須寫一個文檔來說明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語言環境提供了javadoc工具,從而使這個煩瑣的過程變得容易,這個工具可以根據源代碼自動產生API文檔。
為了正確得編寫API文檔,我們必須每一個被導出的類,接口,構造函數,方法和域聲明之前加一個文檔注釋。
每一個方法的文檔注釋應該見解的描述它和客戶之間的約定。