java物件導向程式設計(轉)

ba發表於2007-08-15
java物件導向程式設計(轉)[@more@]Java 的核心是物件導向程式設計。事實上,所有的Java 程式都是物件導向的,你別無選擇。這一點與C++ 不同,因為在那裡你可以選擇是否物件導向程式設計。物件導向程式設計與Java 密不可分,因此,在你編寫哪怕是最簡單的Java 程式以前,也必須理解它的基本原則。因此,本章先從物件導向程式設計的概念講起。
1 兩種範型
我們知道,所有的計算機程式都由兩類元素組成:程式碼和資料。此外,從概念上講,程式還可以以它的程式碼或是資料為核心進行組織編寫。也就是說,一些程式圍繞“正在發生什麼”編寫,而另一些程式則圍繞“誰將被影響”編寫。這兩種範型決定程式的構建方法。第一種方法被稱為程式導向的模型(process -oriented model ),用它編寫的程式都具有線性執行的特點。程式導向的模型可認為是程式碼作用於資料,像C這樣的過程式語言採用這個模型是相當成功的。然而,正如在第1章提到的,當程式變得更大並且更復雜時,就會出現問題。
為了管理不斷增加的複雜性,第二種方式,也就是物件導向的程式設計(object-oriented programming )被構思出來了。物件導向的程式設計圍繞它的資料(即物件)和為這個資料嚴格定義的介面來組織程式。物件導向的程式實際上是用資料控制對程式碼的訪問。下面你將看到,將控制的實體變換為資料,可使程式在組織結構上從若干方面受益。
2 抽象
物件導向程式設計的一個實質性的要素是抽象。人們透過抽象(abstraction)處理複雜性。例如,人們不會把一輛汽車想象成由幾萬個互相獨立的部分所組成的一套裝置,而是把汽車想成一個具有自己獨特行為的物件。這種抽象使人們可以很容易地將一輛汽車開到雜貨店,而不會因組成汽車各部分零件過於複雜而不知所措。他們可以忽略引擎、傳動及剎車系統的工作細節,將汽車作為一個整體來加以利用。
使用層級分類是管理抽象的一個有效方法。它允許你根據物理意義將複雜的系統分解為更多更易處理的小塊。從外表看,汽車是一個獨立的物件。一旦到了內部,你會看到汽車由若干子系統組成:駕駛系統,制動系統,音響系統,安全帶,供暖,便攜電話,等等。再進一步細分,這些子系統由更多的專用元件組成。例如,音響系統由一臺收音機、一個CD播放器、或許還有一臺磁帶放音機組成。從這裡得到的重要啟發是,你透過層級抽象對複雜的汽車(或任何另外複雜的系統)進行管理。
複雜系統的分層抽象也能被用於計算機程式設計。傳統的程式導向程式的資料經過抽象可用若干個組成物件表示,程式中的過程步驟可看成是在這些物件之間進行訊息收集。這樣,每一個物件都有它自己的獨特行為特徵。你可以把這些物件當作具體的實體,讓它們對告訴它們做什麼事的訊息作出反應。這是物件導向程式設計的本質。
物件導向的概念是Java 的核心,對程式設計師來講,重要的是要理解這些概念怎麼轉化為程式。你將會發現,在任何主要的軟體工程專案中,軟體都不可避免地要經歷概念提出、成長、衰老這樣一個生命週期,而物件導向的程式設計,可以使軟體在生命週期的每一個階段都處變不驚,有足夠的應變能力。例如,一旦你定義好了物件和指向這些物件的簡明的、可靠的介面,你就能很從容很自信地解除或更替舊系統的某些組成部分。
3 物件導向程式設計的3個原則
所有物件導向的程式語言都提供幫助你實現物件導向模型的機制,這些機制是封裝,繼承及多型性。現在讓我們來看一下它們的概念。
封裝
封裝(Encapsulation )是將程式碼及其處理的資料繫結在一起的一種程式設計機制,該機制保證了程式和資料都不受外部干擾且不被誤用。理解封裝性的一個方法就是把它想成一個黑匣子,它可以阻止在外部定義的程式碼隨意訪問內部程式碼和資料。對黑匣子內程式碼和資料的訪問透過一個適當定義的介面嚴格控制。如果想與現實生活中的某個事物作對比,可考慮汽車上的自動傳送。自動傳送中包含了有關引擎的數百位元的資訊,例如你正在以什麼樣的加速度前進,你行駛路面的坡度如何,以及目前的檔位。作為使用者,你影響這個複雜封裝的方法僅有一個:移動檔位傳動杆。例如,你不能透過使用拐彎訊號或擋風玻璃擦拭器影響傳動。所以檔位傳動杆是把你和傳動連線起來的惟一介面。此外,傳動物件內的任何操作都不會影響到外部物件,例如,檔位傳動裝置不會開啟車前燈!因為自動傳動被封裝起來了,所以任何一家汽車製造商都可以選擇一種適合自己的方式來實現它。然而,從司機的觀點來看,它們的用途都是一樣的。與此相同的觀點能被用於程式設計。封裝程式碼的好處是每個人都知道怎麼訪問它,但卻不必考慮它的內部實現細節,也不必害怕使用不當會帶來負面影響。
Java 封裝的基本單元是類。儘管類將在以後章節詳細介紹。現在仍有必要對它作一下簡單的討論。一個類(class)定義了將被一個物件集共享的結構和行為(資料和程式碼)。一個給定類的每個物件都包含這個類定義的行為和結構,好像它們是從同一個類的模子中鑄造出來似的。因為這個原因,物件有時被看作是類的例項(instances of a class )。所以,類是一種邏輯結構,而物件是真正存在的物理實體。
當建立一個類時,你要指定組成那個類的程式碼和資料。從總體上講,這些元素都被稱為該類的成員(members )。具體地說,類定義的資料稱為成員變數(member variables)或例項變數(instance variables )。運算元據的程式碼稱為成員方法(member methods )或簡稱方法(methods )。如果你對C/C++ 熟悉,可以這樣理解:Java 程式設計師所稱的方法,就是C/C++ 程式設計師所稱的函式(function )。在完全用Java 編寫的程式中,方法定義如何使用成員變數。這意味著一個類的行為和介面是透過方法來定義的,類這些方法對它的例項資料進行操作。
既然類的目的是封裝複雜性,在類的內部就應該有隱藏實現複雜性機制。類中的每個方法或變數都可以被標記為私有(private )或公共(public )。類的公共介面代表類的外部使用者需要知道或可以知道的每件事情;私有方法和資料僅能被一個類的成員程式碼所訪問,其他任何不是類的成員的程式碼都不能訪問私有的方法或變數。既然類的私有成員僅能被程式中的其他部分透過該類的公共方法訪問,那麼你就能保證不希望發生的事情就一定不會發生。當然,公共介面應該小心仔細設計,不要過多暴露類的內部內容(見圖2-1 )。

圖2-1 封裝:可用來保護私有資料的公共方法
繼承
繼承(Inheritance )是一個物件獲得另一個物件的屬性的過程。繼承很重要,因為它支援了按層分類的概念。如前面提到的,大多數知識都可以按層級(即從上到下)分類管理。例如,尊貴的獵犬是狗類的一部分,狗又是哺乳動物類的一部分,哺乳動物類又是動物類的一部分。如果不使用層級的概念,我們就不得不分別定義每個動物的所有屬性。使用了繼承,一個物件就只需定義使它在所屬類中獨一無二的屬性即可,因為它可以從它的父類那兒繼承所有的通用屬性。所以,可以這樣說,正是繼承機制使一個物件成為一個更具通用類的一個特定例項成為可能。下面讓我們更具體地討論這個過程。
大多數人都認為世界是由物件組成的,而物件又是按動物、哺乳動物和狗這樣的層級結構相互聯絡的。如果你想以一個抽象的方式描述動物,那麼你可以透過大小、智力及骨胳系統的型別等屬性進行描述。動物也具有確定的行為,它們也需要進食、呼吸,並且睡覺。這種對屬性和行為的描述就是對動物類的定義。
如果你想描述一個更具體的動物類,比如哺乳動物,它們會有更具體的屬性,比如牙齒型別、乳腺型別等。我們說哺乳類動物是動物的子類(subclass ),而動物是哺乳動物的超類(superclass )。

由於哺乳動物類是需要更加精確定義的動物,所以它可以從動物類繼承(inherit )所有的屬性。一個深度繼承的子類繼承了類層級(class hierarchy )中它的每個祖先的所有屬性。
繼承性與封裝性相互作用。如果一個給定的類封裝了一些屬性,那麼它的任何子類將具有同樣的屬性,而且還新增了子類自己特有的屬性(見圖2-2 )。這是物件導向的程式在複雜性上呈線性而非幾何性增長的一個關鍵概念。新的子類繼承它的所有祖先的所有屬性。它不與系統中其餘的多數程式碼產生無法預料的相互作用。
多型性
多型性(Polymorphism ,來自於希臘語,表示“多種形態”)是允許一個介面被多個同類動作使用的特性,具體使用哪個動作與應用場合有關,下面我們以一個後進先出型堆疊為例進行說明。假設你有一個程式,需要3種不同型別的堆疊。一個堆疊用於整數值,一個用於浮點數值,一個用於字元。儘管堆疊中儲存的資料型別不同,但實現每個棧的演算法是一樣的。如果用一種非物件導向的語言,你就要建立3個不同的堆疊程式,每個程式一個名字。但是,如果使用Java ,由於它具有多型性,你就可以建立一個通用的堆疊程式集,它們共享相同的名稱。
多型性的概念經常被說成是“一個介面,多種方法”。這意味著可以為一組相關的動作設計一個通用的介面。多型性允許同一個介面被必於同一類的多個動作使用,這樣就降低了程式的複雜性。選擇應用於每一種情形的特定的動作(specific action )(即方法)是編譯器的任務,程式設計師無需手工進行選擇。你只需記住並且使用通用介面即可。

圖2-2 拉不拉多獵犬繼承所有其超類的封裝
再拿狗作比喻,一條狗的嗅覺是多型的。如果狗聞到貓的氣味,它會在吠叫並且追著它跑。如果狗聞到食物的氣味,它將分泌唾液並向盛著食物的碗跑去。兩種狀況下是同一種嗅覺器官在工作,差別在於聞到了什麼氣味,也就是有兩種不同型別的資料作用於狗的鼻子!在一個Java 程式中使用方法時,也可以採用這個通用的概念。
多型性、封裝性與繼承性相互作用
如果用得當,在由多型性、封裝性和繼承性共同組成的程式設計環境中可以寫出比程式導向模型環境更健壯、擴充套件性更好的程式。精心設計的類層級結構是重用你花時間和努力改進並測試過的程式的基礎,封裝可以使你在不破壞依賴於類公共介面的程式碼基礎上對程式進行升級遷移,多型性則有助於你編寫清楚、易懂、易讀、易修改的程式。
在前面兩個與現實生活有關的例項中,汽車更能全面說明物件導向設計的優點,為介紹繼承而用狗作類比也很有趣。總的來說,汽車與程式很相似,所有的駕駛員依靠繼承性很快便能掌握駕駛不同型別(子類)車輛的技術。不管是接送學生的校車,或是默西迪斯私家轎車,或是保時捷汽車,或是家庭汽車,司機差不多都能找到方向盤、制動閘和加速器,並知道如何操作。經過一段駕駛,大多數人甚至能知道手動檔與自動檔之間的差別,因為他們從根本上理解這兩個檔的超類—— 傳動。
人們在汽車上看見的總是封裝好的特性。剎車和踏腳板隱蔽著不可思議的複雜性,但介面卻是如此簡單,你的腳就可以操作它們!引擎、制動閘及輪胎的大小對於你如何定義踏腳板類的介面沒有任何影響。
最後的屬性,多型性,在汽車製造商基於相同的交通工具所提供的多種選擇的能力上得到了充分反映。例如,剎車系統有正鎖和反鎖之分,方向盤有帶助力或不帶助力之分,引擎有4缸、6缸或8缸之分。無論設定如何,你都得腳踩剎車板來停車,轉動方向盤來轉向,按離合器來制動。同樣的介面能被用來控制許多不同的實現過程。
正如你所看到的,透過封裝、繼承及多型性原理,各個獨立部分組成了汽車這個物件。這在計算機程式設計中也是一樣的。透過物件導向原則的使用,可以把程式的各個複雜部分組合成一個一致的、健壯的、可維護的程式整體。
正如本節開始時提到的,所有的Java 程式都是物件導向的。或者,更精確地說,每個Java 程式都具有封裝性、繼承性及多型性。儘管在本章將要介紹的簡單示例程式及以後幾章的示例程式中並未體現所有這些特性,但也有所體現。你將看到,Java 提供的許多特性是它的內建類庫的一部分,這個庫使封裝性、繼承性及多型性得到更廣泛應用。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-958080/,如需轉載,請註明出處,否則將追究法律責任。

相關文章