|
NO.15 要么專門為繼承而設(shè)計(jì),并給出文檔說明,要么禁止繼承 對(duì)并沒有文檔說明的類進(jìn)行繼承是非常危險(xiǎn)的,它的公有方法有可能被改變。在設(shè)計(jì)一個(gè)專門用來繼承的類時(shí)必須注意以下幾點(diǎn)(不適用于final類): ①必須精確地描述改寫每個(gè)方法帶來的影響,雖然這樣的描述違法了文檔格言“好的API文檔應(yīng)該描述一個(gè)方法做了什么工作,而不是描述它如何做”,但這也是繼承破壞了程序的封裝性而導(dǎo)致的。 ②允許繼承的類的構(gòu)造函數(shù)一定不能調(diào)用可被改寫的方法,無論是直接進(jìn)行還是間接進(jìn)行。因?yàn)槌惖臉?gòu)造函數(shù)會(huì)在子類的構(gòu)造函數(shù)之前運(yùn)行,所以子類中改下版本的方法將會(huì)在子類的構(gòu)造函數(shù)運(yùn)行之前就被調(diào)用。如:
“函數(shù)一定不能調(diào)用可被改寫的方法”的實(shí)現(xiàn)方式:把每個(gè)可改寫的方法的代碼體移到一個(gè)私有的“輔助方法”中,并且讓每個(gè)可改寫的方法調(diào)用他的私有輔助方法,然后用“直接調(diào)用可改寫方法的私有輔助方法”來代替“可改寫方法的每個(gè)自用調(diào)用”。 在為了繼承而設(shè)計(jì)類的時(shí)候,不推薦實(shí)現(xiàn)Cloneable和Serializable接口。clone和readObject方法在行為上和構(gòu)造函數(shù)相似——“一定不能調(diào)用可被改寫的方法,無論是直接進(jìn)行還是間接進(jìn)行”,對(duì)于readObject方法,子類中改寫版本的方法將子類的狀態(tài)被反序列化之前運(yùn)行,而對(duì)于clone方法,改寫版本的方法將在子類的clone方法有機(jī)會(huì)修正被克隆對(duì)象的狀態(tài)之前被運(yùn)行,無論哪種情形,它們都會(huì)不可避免的導(dǎo)致程序失敗。 對(duì)于既不是final類,也不是為了子類化而設(shè)計(jì)和編寫文檔的普通類而言,防止出現(xiàn)問題的最好方法是禁止子類化,方法有兩種: ①把這個(gè)類聲明為final的。 ②把所有的構(gòu)造函數(shù)變成私有的,或者包級(jí)私有的,并增加一個(gè)公有的靜態(tài)工廠方法來代替構(gòu)造函數(shù)。 繼承的另一個(gè)替代方案就是利用包裝類模式,具體參見NO.14 復(fù)合優(yōu)先于繼承
NO.16 接口優(yōu)于抽象類 接口和抽象類的區(qū)別: ①抽象類允許包含默寫方法的實(shí)現(xiàn),而接口是不允許的; ②一個(gè)類要實(shí)現(xiàn)抽象類,它必須成為抽象類的一個(gè)子類,而實(shí)現(xiàn)接口的類只要定義了所要求的方法,并遵守通用的約定,不管這個(gè)類位于類層次的哪個(gè)地方; 接口可以構(gòu)造出非層次結(jié)果的類型框架,比如一個(gè)接口可以繼承多個(gè)其他的接口。還可以安全地增加一個(gè)類的功能。 當(dāng)然,也可以把接口和抽象類的有點(diǎn)結(jié)合起來,對(duì)于你期望導(dǎo)出的每一個(gè)總要的接口,頭提供一個(gè)抽象的骨架實(shí)現(xiàn)類,這樣,接口的作用仍然是定義類型,骨架實(shí)現(xiàn)類負(fù)責(zé)所以與接口實(shí)現(xiàn)相關(guān)的工作。 抽象類也有明顯的優(yōu)勢,它可以在一個(gè)類的后續(xù)的版本中方便的增加一個(gè)新的方法,但不影響到其他相關(guān)的類,而接口則做不到這一點(diǎn)。 總之,接口通常是定義具有多個(gè)實(shí)現(xiàn)類型的最佳途徑(例外的情況:當(dāng)演化的容易性比靈活性和功能更為重要的時(shí)候,應(yīng)該使用抽象類來定義類型,但也必須理解抽象類的局限性,并確??梢越邮苓@些局限性),如果已經(jīng)導(dǎo)出了一個(gè)重要的接口,那么,也應(yīng)該考慮同時(shí)提供一個(gè)骨架實(shí)現(xiàn)類。最后,應(yīng)該盡可能的謹(jǐn)慎設(shè)計(jì)所有的公有接口,并通過編寫多個(gè)實(shí)現(xiàn)來對(duì)它們進(jìn)行全面的測試。
NO.17 接口只是被用于定義類型 接口只是用來定義一個(gè)類型,不要把接口用來做其他的事情(如在接口中定義常量,這種常量接口模式是對(duì)接口的不良使用)。 如果要導(dǎo)出常量,可以有以下幾種方式: ①如果這些常量與某個(gè)已有的類或者接口有著緊密的聯(lián)系,則可以把常量添加到這個(gè)類或者接口中。 ②定義一個(gè)類型安全的枚舉類,把這些常量看做枚舉類型的成員。 ③使用一個(gè)可以實(shí)例化的工具類(構(gòu)造函數(shù)設(shè)為privat類型)來導(dǎo)出這些常量。 |
|
|