#分享 (更)【閒聊】Java真的應該被歸類為「物件導向程式語言」嗎?許多人都誤解了「物件導向」的意義,就連學校老師也教錯了

2022年1月27日 00:43
更新的內容在 B14 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 前言: 前陣子看了一篇國外文章,那篇文章對於「物件導向」的詮釋顛覆了許多人的認知,但非常有道理,我覺得寫得不錯。今天我想要來完整的跟各位分享我看完那篇文章後的心得與感悟。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 正文: 我們可能經常在教科書或論壇看到「程式語言可分為物件導向程式語言、程序導向程式語言和函數導向程式語言」的說法。首先,這種說法其實誤導了許多程式學習者,因為這種歸類方式非常不合理,它將程式語言想得過於簡單了。一個語言究竟是物件導向、程序導向還是函數導向,完全取決於程式設計者如何使用那個語言。 舉例來說,JavaScript既可以被寫得非常物件導向,也可以被寫得非常函數導向,圖1和圖2分別展示JavaScript物件導向和函數導向的寫法,兩個程式的功能是一樣的。此外,JavaScript甚至可以混合物件導向和函數導向的風格,著名的例子就是React元件的開發,如圖3所示。 (圖1)
imgur
(圖2)
imgur
(圖3)
imgur
被許多人視為最經典的物件導向程式語言之一的Java也可以寫得非常函數導向,如下方的兩張圖所示,只不過大部分的人都以物件導向的方式來開發Java。
imgur
imgur
Python也經常被視為物件導向程式語言,但它也可以寫得非常函數導向,如下圖所示。
imgur
就連Lisp(被許多人視為函數導向程式語言的代表)也可以用來寫出非常物件導向的程式碼。總而言之,一個語言是不是屬於某一種類型,並不是絕對的,這種歸類方式對於學習程式語言完全沒有意義。更準確一點的說法是,一個程式語言應該被視為「許多語言特性的組合」。對一門程式語言的學習應該拆分成對其每一個「語言特性」的學習,對這些特性一一理解透徹,如此方能掌握這門語言的精髓,之後當學習一門新的語言時,就會發現雖然語法不一樣,但許多語言特性都已經會了,所以只要將學習焦點放在那些沒學過的特性即可,如此一來,可大幅提高學習效率。至於什麼是語言特性呢?下面列出3個例子來說明。 第一個例子是靜態型別檢查(在程式執行前,對它進行型別檢查,這通常由編譯器負責)。Java具備這個特性,但Python和JavaScript不具備,它們採用的是動態型別檢查。靜態型別檢查讓Java得以預先防止bug的出現,使得執行Python或JavaScript時可能會遇到的問題根本不可能在執行Java時發生。 第二個例子是型別推論(即使沒有出現型別的宣告,編譯器仍可推導出型別,並進行靜態型別檢查)。Java不具備這個特性,但OCaml具備,所以不能單憑一個語言跟Python很像,都不需要手動宣告型別,便斷定該語言跟Python一樣,沒有採用靜態型別檢查。 第三個例子是高階函數(higher-order function)。高階函數可以被指定給一個變數(圖4和圖5分別展示Python和JavaScript將函數存入一個變數的例子),可以作為另一個函數的參數(圖6展示Python讓函數作為另一個函數的參數的例子),也可以回傳一個函數(圖11展示Python讓函數回傳一個函數的例子)。Java以前不支援這個特性,Java 8推出後,才開始支援這個特性,但支援的力度比不上JavaScript,所以如果在學Java之前已經熟悉JavaScript的高階函數,那麼學習Java的高階函數必定非常容易。圖7、圖8、圖9和圖10展示Java讓方法作為另一個方法的參數的例子,圖12則展示Java讓方法回傳一個方法的例子。 (圖4)
imgur
(圖5)
imgur
(圖6)
imgur
(圖7)
imgur
(圖8)
imgur
(圖9)
imgur
(圖10)
imgur
(圖11)
imgur
(圖12)
imgur
那麼究竟什麼是「物件導向」呢?雖然有些人也知道Java不是物件導向程式語言,但他們並不認為這是因為將Java歸類為物件導向程式語言不太正確,而是覺得Java之所以不是物件導向程式語言,是因為Java有支援不是物件的基本資料型態(byte、short、int、long、float、double、char、boolean)。這種說法也蠻常看到的,並不能說它錯,但這樣的解釋只涉略到程式語言非常粗淺的部分,沒有真正涉略到物件導向的本質。 大部分的人對於物件導向的理解都非常片面,對於「物件導向」究竟是什麼,一直以來都有諸多爭論。可能有許多人認為類別是物件導向的本質,畢竟類別在Java和C++當中與物件導向有很大的關聯,但其實類別並不是物件導向的本質,理由很簡單,因為有些語言不需要透過類別便能建立一個物件,舉例來說,在JavaScript當中,只要對一個函數new一下,就可以建立一個物件,如下圖所示。所以物件導向根本不需要類別,但也因為類別是許多人使用Java來實作物件導向時非常重要的元素,所以這讓很多人誤以為物件導向一定需要類別,進而更誤以為Java是物件導向程式語言。類別只不過讓Java程式可以更容易達到物件導向。
imgur
比較學術一點的定義會把物件導向圍繞在三個特性:封裝、多型、繼承。這種說法也蠻廣為流傳的,但其實物件導向並沒有這麼複雜。說白一點,物件導向可視為一種「整理程式碼的方式」,而它的核心概念其實是「訊息」,與「物件」並無直接關係。雖然這麼說很矛盾,畢竟「物件導向」就是叫做「『物件』導向」,但艾倫·凱(曾獲得圖靈獎的電腦科學家,「物件導向」這個專有名詞的創造者)並不是這麼說的,由圖13當中被我反白的那段文字可知,他認為物件導向不一定要跟物件有直接關係。他甚至對於使用「物件」這個詞誤導了很多人感到很抱歉,如圖14所示。 (圖13)
imgur
(圖14)
imgur
下方列出更多艾倫·凱對物件導向的理解。從他的描述當中,可看到他對「訊息」的多次強調,而他完全沒提到類別、方法、繼承等等的字眼。所以「訊息」其實才是物件導向的本質,物件導向應該改名為「訊息導向」才對。如果只知道封裝、多型和繼承,恐怕很難從中推敲出「訊息」這個本質。
imgur
imgur
簡單來說,訊息是物件運作的動力來源,物件之間是透過訊息來溝通。沒有了訊息,物件的存在是沒有意義的,就像人如果無法和外界溝通(傳遞、處理訊息),那麼和植物人沒什麼兩樣,所以訊息是物件不可或缺的一項特性。在艾倫·凱的眼中,世界就是一堆獨立運作的物件在互相傳遞和處理訊息。 訊息是用來告訴一個物件去執行某個方法,而物件可透過處理訊息來改變其狀態。假設有兩個物件的名稱分別是a和b,且a向b發送訊息,當b收到a傳遞的訊息後,b必須執行對應的方法來處理那則訊息。在Java當中就相當於a呼叫b的某個方法。舉個現實生活當中的例子,假設有一個男生想要約心儀的女生出去吃飯,他必須先向那個女生傳遞訊息,而這個訊息得包含約會對象、約會方式(吃飯)和約會地點(例如信義區的莫爾頓牛排館),女生接到這個訊息後才能有所回應。至於封裝、多型和繼承則是「實現物件導向的方式」,雖然它們不是物件導向的本質,但的確是實作物件導向的必要元素。 物件可以被視為「黑箱」,因為訊息對物件來說,會對物件本身造成改變,但是並沒有特別指出該如何執行這個改變。加油機就是一個黑箱的例子。用加油機選擇無鉛汽油時,只要加油機運作正常,就不需要了解這部機器是怎麼選定正確價格和油品。這個黑箱的概念就是一個「封裝」的例子,亦即所有的屬性和方法自成一體,物件只能發送或接收訊息,看不到其它物件的內部狀態,自然也不能將其直接更改。 同一個訊息被不同物件接收時,處理方式可能會不一樣,這就是「多型」。舉例來說,「晚安」的訊息是告訴媽媽去讀一篇床邊故事,但對小孩而言是告訴他準備上床睡覺了。 一開始艾倫·凱提出物件導向的概念時,並不是將它視為程式設計的方法,如下圖所示,不過目前大部分的人都已把物件導向當作一種程式設計的方式了。總而言之,硬要糾結於一個程式語言是否為物件導向程式語言以及物件導向到底是什麼其實並沒有太大的意義,能夠適時的將物件導向的概念應用於自己所寫的程式,讓它能更有效率的被執行、使用和維護才是最重要的😊。
imgur
說了這麼多,總歸來說,就是一句話:「不要再說Java是物件導向程式語言了!」
愛心哈哈WOW
61
留言 22
文章資訊