我們這一個世代的程式設計者,在上大學的年紀,正好遇上了物件導向程式設計的觀念開始普及、落實在日常生活的開發當中。我們若是在大學之前受過程式設計的訓練,那麼多半都是基於程序式的程式設計概念。記得那時物件導向的程式設計方式,不僅在國外開始風行起來,連在臺灣也已經開始生根發芽。記得當時由賀元、劉燈、及賴明宗所著的《世紀末軟體革命》出版後,深得國內程式設計者的喜愛,也為一些取得外文資訊不易的設計者,帶來國外新的思潮。

在《世紀末軟體革命》一書中,探討的一些主題包括了物件導向的觀念、C++、GUI等等,對於一些從未接觸過的設計者來說,可以說是耳目一新。從這書名中的「革命」一詞,其實可以窺看當時的程式設計者,以及軟體從業者對於「物件導向」的期待。

許多的程式設計者都希望透過導入物件導向的觀念,解決以往諸多在軟體開發上的問題,諸如開發的生產力、品質、等等。

物件導向觀念日益普遍
從那個時候開始,隨著C++的流行,物件導向的觀念隨著這個能匹配當時個人電腦效能的物件導向語言的興起,也快速進到許多程式設計者的生活。不過幾年間,它已成當代顯學。

隨著網際網路普及,師法C++、並加以改良的Java程式語言,同樣基於物件導向的觀念,但朝純粹的物件導向更靠近。之後Java獲得的成功有目共睹。時至今日,Java仍是受歡迎程式語言排行榜首位的常客。

而在微軟陣營也發展了C#,同樣基於Java改良。此外,一直是早期重要的物件導向程式語言之一的ObjC(Objective-C),隨著Apple的iOS橫掃行動裝置運算市場,程式語言也因為平臺而變得重要。

同樣的,在受歡迎的程式語言排行榜上,絕大多數都是由物件導向的程式語言所支配著。物件導向的設計方式,幾乎可說是當今主流。在今天,物件導向,似乎就像程式設計界的空氣和水一樣,有著不可或缺的地位。

對於物件導向設計的反省

不過,儘管如此,不喜歡物件導向的設計者,仍是大有人在,其中甚至不乏一些大師級的人物。好比電腦科學領域的大師、Touring Award得主的Edsger Dijkstra,也曾說過:「物件導向程式設計是個超爛的想法,只有加州(意指矽谷)的人才想得出來」。

使用某種設計的典範(paradigm)大多時候,和文化、個人的偏好習性都有關係。符合你的偏好,才能讓你運用起來如魚得水,自由自在。反之,那可能就是處處受挫,無法得心應手。當然,不少聲譽卓著的大師級人物對物件導向,頗多怨言,不單只是「調性不合」的原因。然而距離物件導向開始普及至今,也經過了不少年頭。即使是喜受物件導向的設計者,也對物件導向的設計方法有諸多的省思。

究竟,我們所習慣運用的物件導向設計方式,經過了這麼多年的實戰應用及考驗驗證,有那些的確為我們帶來益處?又有那些不如我們所預期,甚至帶來負面的效應呢?

首先,讓我們先來回顧一下物件導向的重要概念及基石。

一般來說,公認物件導向的幾個重要的精神,包括了:資料抽象化、封裝、繼承、以及多型。

一個抽象化的資料型別具有內部的資料結構,以及一些操作用的函式。此型別的使用者,即客戶端程式設計者,只會知道型別的名稱、以及具備存取權限的函式,不會碰觸、也不會了解到內部究竟是如何實作的。因為「抽象化」的設計過程,賦予了這個型別一定的抽象程度,所以,即使實作有所變動,也不會影響到客戶端程式設計者所寫下、相依於這個抽象化資料型別的程式碼。在將資料抽象化後,我們同時希望做到封裝,除了將資料,以及對應操作這些資料的函式,聚集在一個個體之中,也希望透過控制外界的存取權限,來避免曝露太多對外界無關的實作細節。

而繼承則是從物種分類的方式,試著提供一個程式碼重複運用的方法。例如,當我們說某個類別,即抽象化後的資料型別,繼承自另一個類別時,可以直接獲得另一個類別中的資料結構,以及操作資料的函式。除了讓你可重複運用另一個現成類別的程式碼之外,你可能會忽略:繼承也協助設計者針對自己所設計的抽象化資料型別做分類。

事實上,繼承體系本身就是一種對概念分類後的體系,愈靠近體系的「根」,抽象程度愈高,愈接近這個分類樹的「葉」,其抽象程度就愈低。一脈相承的類別,則擁有共通的特性。在父子類別的關係上,父類別代表眾子類別的共通部份,描述的是各個子類別都共通的概念,而各子類別則代表從父類別之下衍生出來的差異部份,代表在共通的基礎之上,可能會有的各種變化。之所以能夠透過繼承來重複運用程式碼,是因為概念上本質有共通的部份,所以父類別中針對共通部份所描述的程式碼,就能夠套用在子類別之上,子類別只需要額外的處理有變異、或是衍生擴充的部份即可。

有些人不是很能理解多型的意思,它不像繼承有很好的比喻,也不像資料抽象化很容易有做為範本的程式碼了解(當然,設計得好不好又是另一回事)。多型的意思是「同一種概念,卻有不同的實際展現」。當我們有了繼承之後,就有了父子類別的關係,其實更具體的說,應該說是一般化概念和特殊化概念的關係。父類別是比較一般化的,描述較為抽象、較為通用的概念,而子類別則是比較特殊化的,描述較為具象的概念。

所以,不同的子類別間有共通的概念,都被描述在父類別裡,但是,各子類別的概念都相同,在實際展現時卻有所不同。例如,液晶電視和傳統電視都有著共通的「電視」概念,但是,它們實際呈現影像的方式不同,這就是「同一種概念,卻有不同的實際展現」。繼承看似有明顯的好處,也就是有直接可重複使用的程式碼。但有些人不是很能善用多型,而多型的好處似乎也不明顯。

在設計的時候,這種讓「同一種概念,有不同的實際展現」究竟能發揮什麼作用呢?事實上,多型關係到你是否能在抽象化的層次,也就是與父類別上得到更多可重複使用的程式碼息息相關。在父類別層所寫下的程式碼,當然是操作子類別間都共通的概念。在實際的應用中,有些共通的概念,即使在子類別上的實際展現也是一樣的,那麼這樣寫下的程式碼,自然可以直接沿用至子類別。但是,有些情況下,在子類別上的實際展現會有些不同,但是父類別仍然必須基於共通的概念來描述這些共通的部份,至於不同的展現,就留待子類別在定義時才完成。

而這讓共通的概念,仍然可以在實際展現未定前,即先行描述完成,同時,也允許在共通的概念下,進行各種可能的展現。這樣基於共通的部份,便可進行無限可能的擴充。

行文至此,我們已簡單地介紹一般認為物件導向的特性,以及應該帶來的優點。但是,在實務的開發過程中,這些特性及優點是否如預期帶來益處,或甚至產生不良的效應呢?在下一回中我們將繼續探討。

作者簡介


Advertisement

更多 iThome相關內容