1. 程式人生 > >面向物件程式設計的基本特徵有哪些?

面向物件程式設計的基本特徵有哪些?

抽象、封裝、繼承、多型

1.抽象
抽象是人們認識事物的常用方法,比如地圖的繪製。抽象的過程就是如何簡化、概括所觀察到的現實世界,併為人們所用的過程。
抽象是軟體開發的基礎。軟體開發離不開現實環境,但需要對資訊細節進行提煉、抽象,找到事物的本質和重要屬性。
抽象包括兩個方面:過程抽象和資料抽象。過程抽象把一個系統按功能劃分成若干個子系統,進行"自頂向下逐步求精"的程式設計。資料抽象以資料為中心,把資料型別和施加在該型別物件上的操作作為一個整體(物件)來進行描述,形成抽象資料型別ADT。
所有程式語言的最終目的都是提供一種"抽象"方法。一種較有爭議的說法是:解決問題的複雜程度直接取決於抽象的種類及質量。其中,"種類"是指準備對什麼進行"抽象"。組合語言是對基礎機器的少量抽象。後來的許多"命令式"語言(如FORTRAN、BASIC和C)是對組合語言的一種抽象。與組合語言相比,這些語言已有了較大的進步,但它們的抽象原理依然要求程式設計者著重考慮計算機的結構,而非考慮問題本身的結構。在機器模型(位於"方案空間")與實際解決的問題模型(位於"問題空間")之間,程式設計師必須建立起一種聯絡。這個過程要求人們付出較大的精力,而且由於它脫離了程式語言本身的範圍,造成程式程式碼很難編寫,而且要花較大的代價進行維護。由此造成的副作用便是一門完善的"程式設計方法"學科。
為機器建模的另一個方法是為要解決的問題製作模型。對一些早期語言來說,如LISP和APL,它們的做法是"從不同的角度觀察世界"、"所有問題都歸納為列表"或"所有問題都歸納為演算法"。PROLOG則將所有問題都歸納為決策鏈。對於這些語言,可以認為它們一部分是面向基於"強制"的程式設計,另一部分則是專為處理圖形符號設計的。每種方法都有自己特殊的用途,適合解決某一類的問題。但只要超出了它們力所能及的範圍,就會顯得非常笨拙。
面向物件的程式設計在此基礎上則跨出了一大步,程式設計師可利用一些工具來表達問題空間內的元素。由於這種表達非常普遍,所以不必受限於特定型別的問題。人們將問題空間中的元素以及它們在方案空間的表示物稱作"物件"。當然,還有一些在問題空間沒有對應體的其他物件。通過新增新的物件型別,程式可進行靈活的調整,以便與特定的問題配合。所以在閱讀方案的描述程式碼時,會讀到對問題進行表達的話語。與以前的方法相比,這無疑是一種更加靈活、更加強大的語言抽象方法。
總之,OOP允許人們根據問題,而不是根據方案來描述問題。然而,仍有一個聯絡途徑回到計算機。每個物件都類似一臺小計算機;它們有自己的狀態,而且可要求它們進行特定的操作。與現實世界的"物件"或者"物體"相比,程式設計"物件"與它們也存在共通的地方:它們都有自己的特徵和行為。
2.封裝
封裝是面向物件程式設計的特徵之一,也是類和物件的主要特徵。封裝將資料以及加在這些資料上的操作組織在一起,成為有獨立意義的構件。外部無法直接訪問這些封裝了的資料,從而保證了這些資料的正確性。如果這些資料發生了差錯,也很容易定位錯誤是由哪個操作引起的。
如果外部需要訪問類裡面的資料,就必須通過介面(Interface)進行訪問。介面規定了可對一個特定的物件發出哪些請求。當然,必須在某個地方存在著一些程式碼,以便滿足這些請求。這些程式碼與那些隱藏起來的資料叫作"隱藏的實現"。站在過程化程式編寫(Procedural Programming)的角度,整個問題並不顯得複雜。一種型別含有與每種可能的請求關聯起來的函式。一旦向物件發出一個特定的請求,就會呼叫那個函式。通常將這個過程總結為向物件"傳送一條訊息"(提出一個請求)。物件的職責就是決定如何對這條訊息作出反應(執行相應的程式碼)。
若任何人都能使用一個類的所有成員,那麼可對這個類做任何事情,則沒有辦法強制他們遵守任何約束--所有東西都會暴露無遺。
有兩方面的原因促使了類的編制者控制對成員的訪問。第一個原因是防止程式設計師接觸他們不該接觸的東西--通常是內部資料型別的設計思想。若只是為了解決特定的問題,使用者只需操作介面即可,無需明白這些資訊。類向用戶提供的實際是一種服務,因為他們很容易就可看出哪些對自己非常重要,以及哪些可忽略不計。進行訪問控制的第二個原因是允許庫設計人員修改內部結構,不用擔心它會對客戶程式設計師造成什麼影響。例如,編制者最開始可能設計了一個形式簡單的類,以便簡化開發。以後又決定進行改寫,使其更快地執行。若介面與實現方法早已隔離開,並分別受到保護,就可放心做到這一點,只要求使用者重新連結一下即可。
封裝考慮的是內部實現,抽象考慮的是外部行為。符合模組化的原則,使得軟體的可維護性、擴充性大為改觀。
3.繼承
繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。物件的一個新類可以從現有的類中派生,這個過程稱為類的繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那裡繼承方法和例項變數,並且派生類可以修改或增加新的方法使之更適合特殊的需求。這也體現了大自然中一般與特殊的關係。繼承性很好地解決了軟體的可重用性問題。比如說,所有的Windows應用程式都有一個視窗,它們可以看作都是從一個視窗類派生出來的。但是有的應用程式用於文書處理,有的應用程式用於繪圖,這是由於派生出了不同的子類,各個子類添加了不同的特性。
關於繼承的詳細討論,將在第4.1~4.2節進行。
4.多型性
多型性是指允許不同類的物件對同一訊息作出響應。比如同樣的加法,把兩個時間加在一起和把兩個整數加在一起肯定完全不同。又比如,同樣的選擇"編輯"、"貼上"操作,在字處理程式和繪圖程式中有不同的效果。多型性包括引數化多型性和執行時多型性。多型性語言具有靈活、抽象、行為共享、程式碼共享的優勢,很好地解決了應用程式函式同名問題。
關於多型性的討論,將在4.7~4.9節進行。
最後,以Alan Kay的話作為本節的結束語。他總結了Smalltalk(這是第一種成功的面向物件程式設計語言,也是Java的基礎語言)的五大基本特徵。通過這些特徵,讀者可以理解"純粹"的面向物件程式設計方法。
(1)所有東西都是物件。可將物件想象成一種新型變數,它儲存著資料,但可要求它對自身進行操作。理論上講,可從要解決的問題上,提出所有概念性的元件,然後在程式中將其表達為一個物件。
(2)程式是一大堆物件的組合。通過訊息傳遞,各物件知道自己該做些什麼。為了向物件發出請求,需向那個物件"傳送一條訊息"。更具體地講,可將訊息想象為一個呼叫請求,它呼叫的是從屬於目標物件的一個子例程或函式。
(3)每個物件都有自己的儲存空間,可容納其他物件。或者說,通過封裝現有物件,可製作出新型物件。所以,儘管物件的概念非常簡單,但在程式中卻可達到任意高的複雜程度。
(4)每個物件都有一種型別。根據語法,每個物件都是某個"類(Class)"的一個"例項"。其中,"類"是"型別(Type)"的同義詞。一個類最重要的特徵就是"能將什麼訊息發給它?"。
(5)同一類所有物件都能接收相同的訊息。這實際是別有含義的一種說法,讀者不久便能理解。由於型別為"圓(Circle)"的一個物件也屬於型別為"形狀(Shape)"的一個物件,所以一個"圓"完全能接收"形狀"的訊息。這意味著可讓程式程式碼統一指揮"形狀",令其自動控制所有符合"形狀"描述的物件,其中自然包括"圓"。這一特性稱為物件的"可替換性",是OOP最重要的概念之一。