Java — 面向對象的編程語言

本篇文章將對 Java 中面向對象的一些概念做出詳細討論。

一、爲什麼要面向對象?

老是在說面向對象,面向對象中的這個對象到底是什麼呢?

1、什麼是對象?

對象是人們可以進行研究的一切事物,從最簡單的一支鉛筆到極其複雜的航空母艦,都可以看作是對象。對象不僅僅能表示具體的事物,還能表示抽象的規則、計劃或者事件等。

因此,面向對象的這個對象,指的是客體。所謂客體指的是客觀存在的對象實體主觀抽象的概念

客體或對象(Object)在哲學上指可感知或可想像到的任何事物,既包括客觀存在並可觀察到的事物(如人物、樹木、房屋,抽象的如物價、自由),也包括想像的事物(如神化人物)。—— 《維基百科》

2、結構化編程

最早的程序開發,使用的都是結構化(面向過程)程序設計語言。

計算機是幫助人們解決問題的,然而計算機終究是個機器,它只會按照人所寫的代碼,一步一步的執行下去,最終得到了結果。**結構化編程,就是按照計算機的思維寫出的代碼。**隨着時間的推移,軟件的規模逐漸擴大,業務邏輯變得越來越複雜的時候,當人再看到這些邏輯時,就無法維護和擴展了。

同時,結構化設計是以功能爲目標來設計構造應用系統的,這種做法導致我們設計程序時,不得不將客體所構成的現實世界映射到由功能模塊組成的軟件系統中,這種轉換過程,背離了人們觀察和解決問題的基本思路。

3、面向對象編程

可見結構化編程在設計系統的時候,無法解決重用、維護、擴展的問題,而且會導致邏輯過於複雜,代碼晦澀難懂的問題。

於是人們就想,能不能讓計算機直接模擬現實的環境,用人類解決問題的思路、習慣和步驟來設計相應的應用程序呢?

於是,程序設計者們將另一種開發思想引入程序中 —— 面向對象編程(Object-Oriented Programming)。 人們在閱讀使用面向對象編程思想編寫的程序時,會更容易理解,也不需要再在現實世界和程序世界之間來回做轉換。

舉個下五子棋的例子。

結構化編程(面向過程)的設計思路就是分析問題的步驟,把每個步驟分別用函數來實現:

  1. 開始遊戲

  2. 黑子先走

  3. 繪製畫面

  4. 判斷輸贏

  5. 輪到白子

  6. 繪製畫面

  7. 判斷輸贏

  8. 返回步驟 2

  9. 輸出最後結果

而面向對象的設計思路是:

  1. 黑白雙方:這兩方的行爲是一模一樣的(玩家對象);
  2. 棋盤系統:負責繪製畫面(棋盤對象);
  3. 規則系統:負責判定諸如犯規、輸贏等(規則對象)。

玩家對象負責接受用戶輸入,並告知棋盤對象棋子佈局的變化,棋盤對象接收到了棋子的變化,負責在屏幕上面顯示出這種變化;同時利用規則對象來對棋局進行判定。

也就是說:先找到對象,然後把它的狀態(屬性)、行爲(方法)全部封裝到一起,隨時調用。

4、面向對象的優點

面向對象程序設計有以下優點:

  1. 可重用性:代碼重複使用,減少代碼量,提高開發效率;
  2. 可擴展性:指新的功能可以很容易地加入到系統中來,便於軟件的修改;
  3. 可維護性:能夠將功能與數據結合,方便維護。

在下面的討論中,我會一一講解這些優點在 Java 中是如何體現的。

二、對象

對象與事物(可感知或可想像到的)是一一對應的,也就是說每一個客體都是一個對象,因此對象具有唯一性(即使是完全相同的兩個對象,也並非同一個對象)。對象是一個具體的概念。

對象具有兩個特徵:

  • 狀態(State
  • 行爲(Behavior

以小狗這個對象來舉例:

  • 狀態:名字、年齡等;
  • 行爲:吠叫、奔跑等。

三、類

什麼是類?

**類是描述了一組有相同特徵(屬性)和相同行爲(方法)的一組對象的集合。**類可以被視爲藍圖(或者模板),使用類可以創建任意多的對象。因此,對象是類的實例。

以小狗爲例,中華田園犬是個對象、柴犬是個對象、哈士奇是個對象、牧羊犬也是個對象,這些小狗具有相同的狀態(屬性)和行爲(方法)。這些一個個的對象屬於同一個種類 —— 狗類,它是一個邏輯實體,而不是一個具體的實物。

Java 語言來描述這個類就是:

public class Dog {
  String name;
  int age;

  void barking() {
    System.out.println("Woof woof woof!");
  }

  void running() {
    System.out.println("I run fast!");
  }
}

Dog 這個類擁有 nameage 這些屬性和 barkingrunning 這些方法,那麼通過 Dog 這個類(模板)創建的對象(實例)都會具有這些屬性(狀態)和方法(行爲)。也就是說類定義了屬於這個類的對象所應該具有的狀態和行爲。

下面對上述代碼示例做一下說明:

  • public 是類的修飾符(後面會講到),表明該類是公共類,可以被其他類訪問;
  • class 是聲明類的關鍵字;
  • Dog 是類名稱;
  • nameage 是類的成員變量(實例變量),也叫屬性(後面會介紹其他類型的變量);
  • barking()running() 是類中的函數,也叫方法。

有了類,怎麼生成實例呢?—— 通過 new 關鍵字。一般有以下三個步驟:

  • 聲明:聲明一個對象,包括對象名稱和對象類型;
  • 實例化:使用關鍵字 new 來創建一個對象。
  • 初始化:使用 new 創建對象時,會調用構造函數(下面會講到)初始化對象。
Dog myDog = new Dog(); 

myDog 就是通過 Dog 這個類實例化成的一個對象。

現在我們知道了什麼是對象、什麼是類。那回到最開始的問題,面向對象編程是如何解決重用、維護、擴展的問題的呢?

四、封裝

前面我們已經知道了對象有屬性和方法兩個特徵。在編程時,把一些數據(屬性)和有關數據的一些操作(方法)綁定在一起,形成一個不可分開的集合(類),這個過程就是封裝(Encapsulation。也就是說,如果你正在創建類,那麼你就是在進行封裝。

封裝背後的思想其實是在向用戶隱藏實現細節。我們把類裏面的屬性私有化,那麼這些屬性就只能在同一個類中訪問,任何外部類都不能訪問;然後向外提供操作數據的公開的方法。當外部需要訪問時,可以不用管類內部的具體邏輯關係,只需要通過調用類內部對應的方法就可以了。這樣可以保證數據的安全性

同時,封裝也有助於建立各個系統之間的松耦合關係,提高系統的獨立性。當一個系統的實現方式發生變化時,只要它的接口不變,就不會影響其他系統的使用。

比如我們使用 ATM 機取錢的時候,只需要插入銀行卡,輸入密碼即可取錢,不用關心是它的內部如何運行或者發生了什麼改變,只要我們可以插卡,可以輸入密碼,就不會影響正常的操作。

當類發生變化時,我們只需要找到變化並且把它繼續封裝起來,就可以在不影響其它部分的情況下修改或擴展被封裝的變化部分,因此就解決了程序的可擴展性

五、繼承

就像生活中,子女可以繼承父母所擁有的的全部財產一樣,Java 裏的**繼承(Inheritance)**是指子類擁有父類的全部特徵和行爲,這也就是類之間的關係。

可以試想一下,以小狗爲例,定義一個哈士奇類和柴犬類,如果不採用繼承的方式,那麼這兩個類裏需要定義的特性(屬性)和行爲(方法)很多都是相同的,代碼會有很多重複和冗餘的地方。如果將一些公有的特性(屬性)和行爲(方法)拿出來封裝在一個類(父類)中,其他類可以通過繼承這個類來得到這些屬性和方法,這樣就不用每次都重新定義了。當然,父類也可以去繼承其它的類,比如狗類可以再去繼承哺乳動物類。因此,繼承也解決了系統的重用性和擴展性。

但是繼承也破壞了封裝,因爲父類是對子類開放的,修改父類會導致所有子類的改變,因此繼承一定程度上又破壞了系統的可擴展性,所以,我們也需要謹慎使用繼承。優先使用組合,而不是繼承,是面向對象開發中一個重要的經驗。

注意,Java 中的繼承是單繼承,也就是說一個子類最多隻能有一個父類。

六、多態

理解多態之前,需要先了解另外一個概念 —— 接口(Interface。什麼是接口呢?比如彩色打印機可以打印,黑白打印機也可以打印,我們可以把打印這個行爲抽離出來,變成一個接口,爲兩個類提供通用的處理服務。也就是說接口是對行爲的抽象

所以,簡單來說,多態Polymorphism)就是同一個行爲具有多個不同表現形式或形態的能力。對應到應用程序中就是同一個接口,使用不同的實例對象而執行不同操作。

如下圖打印機的例子:

printer-polymorphism

我們把打印文件這個方法變成一個接口,讓彩色打印機和黑白打印機都實現這個接口,同一個事件發生在不同的對象上會產生不同的結果。父類中定義的屬性和方法被子類繼承後,可以具有不同的屬性或表現方式。這樣就實現了系統的可擴展性,可維護性也會變強。

七、總結

通過上面的描述,我們知道了面向對象是如何實現系統的可維護性,可擴展性,可重用性,不過只是一些概念性的講解,並沒有落地到代碼層面進行闡述,後面我會結合代碼再做詳細討論。

其實,面向對象是一種編程思想,跟語言沒有什麼關係,只不過有的語言在語言的設計層面,就天然地與面向對象的思想聯繫起來,有類,有繼承,如 JavaC++ ;而像 JavaScript 中並沒有類的概念,也只是通過構造函數和原型鏈的方式來實現繼承,但是我們在使用 JavaScript 編程的時候,依然可以使用面向對象編程思想來編程,讓代碼的可維護性、可擴展性、可重用性變得更好。

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