面向對象編程技術

在現實生活中,我們必須弄明白我們所面對的大量的事實以及觀念。爲此,我們需要從表面細節中抽象出其內在邏輯,發現事物的本質。抽象法可以幫助我們揭示事物的因果,結構和表現形式,區分主要和次要。面向對象編程提供了一種對您所操作的數據進行抽象的方法—而且,面向對象編程將數據和對數據的操作組合到一起,從而使數據具有了行爲。

本部分包含如下內容:


數據和操作

傳統的編程語言通常劃分成兩個部分—數據和對數據的操作。數據是靜態的,不變的,除非通過操作來改變它。對數據操作的函數並不保留上一次操作時數據的狀態,它們的作用僅體現在操作數據上。

很明顯,這種劃分是基於計算機的工作方式,所以您很難忽視它。和無處不在的原料和能量以及名詞和動詞的劃分一樣,它構成了程序的本質。從某種意義上說,所有的程序員—即使是面向對象的程序員—都是工作在數據結構之上,他們的程序也會使用和定義函數來操作數據。

對於面向過程編程語言例如C來說,這幾乎就是一切了。語言本身可能爲組織數據和函數提供了多種支持,但是本質上仍然是分成數據和操作兩個部分。函數和數據結構是設計的基本元素。

面向對象編程當然不會這樣來劃分,而是在更高的層次重新組織。它把操作和數據組合爲一個模塊單元叫做對象 ,並且把對象組成一個結構化的網絡來完成一個程序。在面向對象的編程語言中,對象和對象間的交互纔是設計的基本元素。

每個對象都具有狀態(數據)和行爲(對數據的操作)。也就是說,它們和物理實體並沒有太大區別。一臺機械裝置例如懷錶、鋼琴如何體現自己的狀態和行爲是顯而易見的,然而幾乎每樣功能性的物體都能夠體現自己的狀態和行爲。即使一個普通的瓶子也會有狀態(瓶子有多滿,瓶子是否已經打開,瓶子所裝的液體溫度多少)和行爲(以不同的流量倒出所裝液體,蓋上或者打開,加熱或者製冷)。

正是這種與實物的相似性賦予了對象強大的能力和吸引力。這些對象不僅可以對現實系統的組件建模,也能夠勝任軟件系統中的同樣的角色。


接口和實現

編寫一個程序,您需要對問題進行抽象, 並使用程序將其表達出來。這正是編程語言幫您做的工作。編程語言可以幫助您對抽象後的問題進行編碼從而使得程序的編寫和設計過程更爲簡單。它使您只用關注您所寫的代碼和程序的架構而無需關心表面的細節。

所有的程序語言都提供了對抽象後的問題進行編碼的方法。本質上,這些方法就是怎樣分離並隱藏實現細節,然後至少在某種程度上,提供給這些細節一個公共的接口—就像機械裝置將它的表面和內部的構造分離一樣—如圖"接口和實現"所示。


圖 2-1 接口和實現





隨着對該裝置的觀察角度不同,您所關注的層面也不同。作爲一個實現者,您需要關心它是由什麼構成並且怎樣工作的。作爲一個用戶,您僅需要關心它是什麼並且它能夠做什麼。您可以略過那些具體的細節而從更高層次來考慮問題。

在C語言中,程序的基本單位是結構體和函數,這兩者從不同的方面隱藏了具體實現細節。
從數據方面,C中的結構體把數據組合成一個更大的單位從而可以象一個單獨的實體一樣對它進行操作。儘管有時候代碼需要訪問結構體內部的數據,但程序一般都將結構體作爲一個單獨的數據實體來對待—而不是數據的集合。結構體能包含另一個結構體,從而組成複雜的數據結構。

在現代C語言中,結構體中的數據元素位於該結構體的名字空間—也就是說,結構體內的元素名字不會和結構體外的同名元素衝突。 劃分名字空間對保證實現細節和接口的分離來說是非常必要的。例如,試想一下,在一個大規模的程序中給每個數據元素賦予一個不同的名字並且保證新的命名不會和已存在的命名衝突是一件多麼巨大的工作。
從過程方面,函數封裝了一些可以重複使用而不用重新實現的行爲(操作)。和結構體的數據元素一樣,函數中局部變量也處於該函數自己的名字空間。函數可以調用其他的函數,從而組成複雜的邏輯。

函數是可複用的。一旦函數被定義,則可以不限次的調用而無需再重新實現。一些被廣泛使用的函數可能被收集在函數庫中並且在不同的應用程序中被重用。用戶只需要函數的接口,而不需要知道函數的實現。

然而,和結構體中數據元素不同的是,函數並沒有劃分不同的名字空間。每個函數的名字必須唯一。儘管函數是可複用的,但函數名不是。

C語言中的結構體和函數都能夠幫助您對問題進行抽象,但是它們仍然區分了數據和對數據的操作。在面向過程的編程語言中,問題要麼被抽象成數據,要麼被抽象成操作。您的程序總是按照計算機的工作方式去設計。

面向對象的語言沒有拋棄結構體和函數的優點—它更深入了一步,將問題抽象成更高層次的單位,從而隱藏了函數和數據之間的交互。

例如,假設您有一組函數(接口)作用於某個特定的數據結構。您希望這些數據結構和接口無關從而使得這些函數儘可能的易於使用,所以提供了一些額外的函數來管理這些數據。所有對該數據結構的操作—分配內存空間,初始化,獲取數據,更改數據,更新數據,釋放內存空間—都通過這些額外的函數來進行。用戶所需要做的只是以該數據結構爲參數調用這些函數。

這樣,該數據結構對其他的程序員來說是不透明的,他們無需關心該數據結構的內部構成,從而專注於函數的功能,而不是該數據結構。到現在爲止,您已經完成了創建對象的第一步。

下一步就是在編程語言中支持這一想法並且完全隱藏掉數據結構從而無需在函數中作爲參數來回傳遞。該數據結構成爲一個內部的實現細節,暴露給用戶的是函數接口。因爲對象完全封裝(隱藏)了內部數據,所以用戶只用考慮對象的行爲。

有了這一步,這些函數的接口變得更爲簡單。調用者無需知道函數是怎麼實現的(使用了什麼數據)。現在我們可以把它稱之爲”對象“。

被隱藏的數據結構把所有的訪問自己的函數聯合在一起。所以,一個對象不是一些隨機選擇的函數的集合,而是數據結構支持的一組相關的行爲。要使用一個對象的函數,您必須首先創建一個對象(從而分配了內部數據結構),然後告訴這個對象執行哪個函數。從這時開始,您只需考慮這個對象能做什麼,而不用單獨的考慮這些函數能做什麼。

從函數和數據結構到對象行爲的過程就是學習面向對象編程的精髓。可能一開始有點不習慣,但如果您有了一定的面向對象編程經驗後,您會發現面向對象更符合我們思考問題的自然方式。日常的編程術語中充滿了對現實世界的模擬—表單,容器,表格,控制器,甚至管理者,將這些做爲程序對象來實現也是自然而然的事情。

不同的編程語言對問題抽象的方式也不同。您不應關心和當前問題無關的細節。

例如,如果您總是要求相應的過程必須處理相應的數據,則您將需要知道底層的實現細節。儘管您仍然可以在更高的層次抽象問題,然而,從設計到實現的區別可能變得很細微—而且程序規模越大,越複雜,則設計越困難。

通過對問題不同層次的抽象,面嚮對象語言向您提供了更大的詞彙表和更豐富的編程模型。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章