就其本身來說,對(duì)象的概念可為我們帶來極大的便利。它在概念上允許我們將各式各樣數(shù)據(jù)和功能封裝到一起。這樣便可恰當(dāng)表達(dá)“問題空間”的概念,不用刻意遵照基礎(chǔ)機(jī)器的表達(dá)方式。在程序設(shè)計(jì)語言中,這些概念則反映為具體的數(shù)據(jù)類型(使用class關(guān)鍵字)。
我們費(fèi)盡心思做出一種數(shù)據(jù)類型后,假如不得不又新建一種類型,令其實(shí)現(xiàn)大致相同的功能,那會(huì)是一件非常令人灰心的事情。但若能利用現(xiàn)成的數(shù)據(jù)類型,對(duì)其進(jìn)行“克隆”,再根據(jù)情況進(jìn)行添加和修改,情況就顯得理想多了?!袄^承”正是針對(duì)這個(gè)目標(biāo)而設(shè)計(jì)的。但繼承并不完全等價(jià)于克隆。在繼承過程中,若原始類(正式名稱叫作基礎(chǔ)類、超類或父類)發(fā)生了變化,修改過的“克隆”類(正式名稱叫作繼承類或者子類)也會(huì)反映出這種變化。在Java語言中,繼承是通過extends關(guān)鍵字實(shí)現(xiàn)的
使用繼承時(shí),相當(dāng)于創(chuàng)建了一個(gè)新類。這個(gè)新類不僅包含了現(xiàn)有類型的所有成員(盡管private成員被隱藏起來,且不能訪問),但更重要的是,它復(fù)制了基礎(chǔ)類的接口。也就是說,可向基礎(chǔ)類的對(duì)象發(fā)送的所有消息亦可原樣發(fā)給衍生類的對(duì)象。根據(jù)可以發(fā)送的消息,我們能知道類的類型。這意味著衍生類具有與基礎(chǔ)類相同的類型!為真正理解面向?qū)ο蟪绦蛟O(shè)計(jì)的含義,首先必須認(rèn)識(shí)到這種類型的等價(jià)關(guān)系。
由于基礎(chǔ)類和衍生類具有相同的接口,所以那個(gè)接口必須進(jìn)行特殊的設(shè)計(jì)。也就是說,對(duì)象接收到一條特定的消息后,必須有一個(gè)“方法”能夠執(zhí)行。若只是簡單地繼承一個(gè)類,并不做其他任何事情,來自基礎(chǔ)類接口的方法就會(huì)直接照搬到衍生類。這意味著衍生類的對(duì)象不僅有相同的類型,也有同樣的行為,這一后果通常是我們不愿見到的。
有兩種做法可將新得的衍生類與原來的基礎(chǔ)類區(qū)分開。第一種做法十分簡單:為衍生類添加新函數(shù)(功能)。這些新函數(shù)并非基礎(chǔ)類接口的一部分。進(jìn)行這種處理時(shí),一般都是意識(shí)到基礎(chǔ)類不能滿足我們的要求,所以需要添加更多的函數(shù)。這是一種最簡單、最基本的繼承用法,大多數(shù)時(shí)候都可完美地解決我們的問題。然而,事先還是要仔細(xì)調(diào)查自己的基礎(chǔ)類是否真的需要這些額外的函數(shù)。
1.5.1 改善基礎(chǔ)類
盡管extends關(guān)鍵字暗示著我們要為接口“擴(kuò)展”新功能,但實(shí)情并非肯定如此。為區(qū)分我們的新類,第二個(gè)辦法是改變基礎(chǔ)類一個(gè)現(xiàn)有函數(shù)的行為。我們將其稱作“改善”那個(gè)函數(shù)。
為改善一個(gè)函數(shù),只需為衍生類的函數(shù)建立一個(gè)新定義即可。我們的目標(biāo)是:“盡管使用的函數(shù)接口未變,但它的新版本具有不同的表現(xiàn)”。
1.5.2 等價(jià)與類似關(guān)系
針對(duì)繼承可能會(huì)產(chǎn)生這樣的一個(gè)爭論:繼承只能改善原基礎(chǔ)類的函數(shù)嗎?若答案是肯定的,則衍生類型就是與基礎(chǔ)類完全相同的類型,因?yàn)槎紦碛型耆嗤慕涌凇_@樣造成的結(jié)果就是:我們完全能夠?qū)⒀苌惖囊粋€(gè)對(duì)象換成基礎(chǔ)類的一個(gè)對(duì)象!可將其想象成一種“純替換”。在某種意義上,這是進(jìn)行繼承的一種理想方式。此時(shí),我們通常認(rèn)為基礎(chǔ)類和衍生類之間存在一種“等價(jià)”關(guān)系——因?yàn)槲覀兛梢岳碇睔鈮训卣f:“圓就是一種幾何形狀”。為了對(duì)繼承進(jìn)行測試,一個(gè)辦法就是看看自己是否能把它們套入這種“等價(jià)”關(guān)系中,看看是否有意義。
但在許多時(shí)候,我們必須為衍生類型加入新的接口元素。所以不僅擴(kuò)展了接口,也創(chuàng)建了一種新類型。這種新類型仍可替換成基礎(chǔ)類型,但這種替換并不是完美的,因?yàn)椴豢稍诨A(chǔ)類里訪問新函數(shù)。我們將其稱作“類似”關(guān)系;新類型擁有舊類型的接口,但也包含了其他函數(shù),所以不能說它們是完全等價(jià)的。舉個(gè)例子來說,讓我們考慮一下制冷機(jī)的情況。假定我們的房間連好了用于制冷的各種控制器;也就是說,我們已擁有必要的“接口”來控制制冷?,F(xiàn)在假設(shè)機(jī)器出了故障,我們把它換成一臺(tái)新型的冷、熱兩用空調(diào),冬天和夏天均可使用。冷、熱空調(diào)“類似”制冷機(jī),但能做更多的事情。由于我們的房間只安裝了控制制冷的設(shè)備,所以它們只限于同新機(jī)器的制冷部分打交道。新機(jī)器的接口已得到了擴(kuò)展,但現(xiàn)有的系統(tǒng)并不知道除原始接口以外的任何東西。
認(rèn)識(shí)了等價(jià)與類似的區(qū)別后,再進(jìn)行替換時(shí)就會(huì)有把握得多。盡管大多數(shù)時(shí)候“純替換”已經(jīng)足夠,但您會(huì)發(fā)現(xiàn)在某些情況下,仍然有明顯的理由需要在衍生類的基礎(chǔ)上增添新功能。通過前面對(duì)這兩種情況的討論,相信大家已心中有數(shù)該如何做。