【java基礎(十四)】面向對象程序設計概述

前言

如果你沒有面向對象程序設計的應用背景,就一定概要認真地看一下我接下來的幾個文章。

面向對象程序設計與面向過程程序設計在思維方式上存在很大的差別。

接下來的內容概述性的東西多一些,基本沒有示例,請耐心看完並用心理解,揣摩。

概述

面向對象程序設計(簡稱OOP)是當今主流的程序設計範型,它已經取代了20世紀70年代的“結構化”過程化程序設計開發技術。Java是完全面向對象的,比如熟悉OOP才能夠編寫Java程序。

面向對象的程序是由對象(Object)組成的,每個對象包含對用戶公開的特定部分功能和隱藏的實現部分。程序中的很多對象來自標準庫,還有一些是自定義的。究竟是自己構造對象,還是從外接購買對象完全取決於開發項目的預算和時間。但是,從根本上來說,只要對象能夠滿足要求,就不必關心其功能的具體實現過程。在OOP中,不必關心對象的具體實現,只要能夠滿足用戶的需求即可。

傳統的結構化程序設計通過設計一系列的過程(即算法)來求解問題。一旦確定了這些過程,就要開始考慮存儲數據的方式。這就明確表述了程序員的工作方式。首先要確定如何操作數據,然後再決定如何組織數據,以便於數據操作。而OOP卻調換了這個次序,將數據放在第一位,然後再考慮操作數據的算法。

對於一些規模較小的問題,將其分解爲過程的開發方式比較理想。而面向對象更加適用於解決規模較大的問題。

類(class)是構造對象的模版或藍圖。我們可以將類想象成製作小甜餅的切割機,將對象想象爲小甜餅。由類構造(construct)對象的過程稱爲創建類的實例(instance)。

正如前面所看到的,用Java編寫的所有代碼都位於某個類的內部。標準的Java庫提供了幾千個類,可以用於用於界面設計、日期、日曆和網絡程序設計。儘管如此,還是需要在Java程序中創建一些自己的類,一遍描述應用程序所對應的問題域中的對象。

封裝(encapsulation,有時稱爲數據隱藏)是與對象有關的一個重要概念。從形式上看,封裝不過是將數據和行爲組合在一個包中,並對對象的使用者隱藏了數據的實現方式。對象中的數據稱爲實例域(instance field),操作數據的過程稱爲方法(method)。對於每個特定的類實例(對象)都有一組特定的實例域值。這些值的集合就是這個對象當前狀態(state)。無論何時,只要向對象發送一個消息,它的狀態就有可能發生改變。

實現封裝的關鍵在於絕對不能讓類中的方法直接地訪問其他類的實例域。程序僅通過對象的方法與對象數據進行交互。封裝給對象賦予了“黑盒”特徵,這是提高重用性和可靠性的關鍵。這意味着一個類可以全面地改變存儲數據的方式,只要仍舊使用同樣的方法操作數據,其他對象就不會知道或介意所發生的變化。

OOP的另一個原則會讓用戶自定義Java類變得輕而易舉,這就是:可以通過擴展一個類來建立另外一個新的類。事實上,在Java中,所有的類都源自於一個“神通廣大的超類”,它就是Object。

在擴展一個已有的類時,這個擴展後的新類具有所擴展類的全部屬性和方法。在新類中,只需提供適用於這個新類的新方法和數據域就可以了。通過擴展一個類來建立另外一個類的過程稱爲繼承(inheritance)。

對象

要想使用OOP,一定要清楚對象的三個特性:

  • 對象的行爲(behavior),可以對對象施加哪些操作,或可以對對象施加那些方法。
  • 對象的狀態(state),當施加那些方法時,對象如何響應。
  • 對象標識(identity),如何辨別具有相同行爲與狀態的不同對象。

同一個類的所有對象實例,由於支持相同的行爲而具有家族式的相似性。對象的行爲是用可調用的方法定義的。

此外,每個對象都保存着描述當前特徵的信息。這就是對象的狀態。對象的狀態可能會隨着時間而發生改變,但這種改變不會是自發的。對象狀態的改變必須通過調用方法實現(如果不經過方法調用就可以改變對象狀態,只能說明封裝性遭到了破壞)。

但是,對象的狀態並不能完全描述一個對象。每個對象都有一個唯一的身份(identity)。例如,在一個訂單處理系統中,任何兩個訂單都存在着不同之處,即使所訂購的貨物完全相同也是如此。需要注意,作爲一個類的實例,每個對象的標識永遠是不同的,狀態常常也存在着差異。

對象的這些關鍵特性在彼此之間相互影響着。例如,對象的狀態影響它的行爲(如果一個訂單“已發貨”或“已付款”,就應該拒絕調用具有增刪訂單中條目的方法。反過來,如果訂單是“空的”,即沒有加入預訂的物品,這個訂單就不應該進入“已送貨”的狀態)。

識別類

傳統的過程化程序設計,必須從頂部的main函數開始編寫程序。在面向對象程序設計時沒有所謂的“頂部”。對於學習OOP的初學者來說常常會感覺無從下手。答案是:首先從設計類開始,然後再往每個類中添加方法。

識別類的簡單規則是在分析問題的過程中尋找名詞,而方法對應着動詞。

例如:在訂單處理系統中,有這樣一些名詞:

  • 商品(Item)
  • 訂單(Order)
  • 送貨地址(Shipping address)
  • 付款(Payment)
  • 賬戶(Account)

這些名詞很可能成爲類Item、Order等。

接下來,查看動詞:商品被添加到訂單中,訂單被髮送或取消,訂單貨款被支付。對於每一個動詞如:“添加”、“發送”、“取消”以及“支付”,都要標識出主要負責完成相應動作的對象。例如,當一個新的商品添加到訂單中時,那個訂單對象就是被指定的對象,因爲它知道如何存儲商品以及如何對商品進行排序。也就是說,add應該是Order類的一個方法,而Item對象是一個參數。

當然,所謂“找名詞與動詞”原則只是一種經驗,在創建類的時候,哪些名詞和動詞是重要的完全取決於個人的開發經驗。

類之間的關係

在類之間,最常見的關係有

  • 依賴(“uses-a”)
  • 聚合(“has-a”)
  • 繼承(“is - a”)

依賴(dependence),即“users-a”關係,是一種最明顯的、最常見的關係。例如,Order類使用Accound類是因爲Order對象需要訪問Account對象查看信用狀態。但是Item類不依賴Account類,這是因爲Item對象與客戶無關。因此,如果一個類的方法操縱另一個類的對象,我們就說一個類依賴於另一個類。

應該儘可能地將相互依賴的類減至最少。如果類A不知道B的存在,它就不會關心B的任何改變(這意味着B的改變不會導致A產生任何bug)。用軟件工程的術語來說,就是讓類之間的耦合度最小。

聚合(aggregation),即“has-a”關係,是一種具體且易於理解的關係。例如,一個Order對象包含一些Item對象。集合關係意味着類A的對象包含類B的對象。

繼承(inheritance),即“is-a”關係,是一種用於表示特殊與一般關係的。例如,RushOrder類由Order類繼承而來。在具有特殊性的RushOrder類中包含了一些用於優先處理的特殊方法,以及一個計算運費的不通方法;而其他的方法,如添加商品、生成賬單等都是從Order類繼承來的。一般而言,如果類A擴展類B,類A不但包含從類B繼承的方法,還會擁有一些額外的功能。

想要說的話

  • 都是概念,概念就要慢慢理解,不要睡着了就好。
  • 寫一輩子Java之後會發現,一直都是圍繞着這些概念在搞事情。

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章