面向對象編程已死?

本文最初發表於 Towards Data Science 博客,經原作者 Rhea Moutafis 授權,InfoQ 中文站翻譯並分享。

在 20 世紀 60 年代,編程有一個很大的問題:計算機還遠沒有那麼強大,而且不知何故,它們還需要在數據結構和過程之間以某種方式分配容量

這意味着,如果你有大量數據的話,你就不能用它做那麼多的事情,否則就會把計算機逼到極限。而另一方面,如果你需要做很多事情,你就不能使用太多的數據,否則計算機將會耗費大量時間。

後來,Alan Lay 在 1966 年或 1967 年提出了一個理論,即人們可以使用封裝起來的微型計算機,這種計算機並不共享數據,而是通過消息傳遞並進行通信。通過這種方式,可以做到更經濟地使用計算資源。

儘管這個想法很有創意,但直到 1981 年,面向對象編程才成爲主流。然而,從那時起,它就一直吸引着新入門的和經驗豐富的軟件開發人員。面向對象的程序員市場一如既往地繁忙。

但近年來,這一有着十年曆史的範式受到了越來越多的批評。有沒有可能,在面向對象編程普及四十年後,技術已經超越了這種方式?

耦合函數與數據有那麼愚蠢嗎?

面向對象編程背後的主要思想非常簡單:試圖將一個程序分解成與整體一樣強大的部分。接下來,你需要將數據片段和那些僅在相關數據上使用的函數耦合在一起。

請注意,這僅僅只是涵蓋了封裝的概念,也就是說,位於對象內部的數據和函數對外部都是不可見的。人們只能通過消息與對象的內容進行交互,通常稱爲gettersetter函數。

最初的想法中沒有包含的,但被認爲是當今面向對象編程必不可少的是:繼承和多態性。繼承基本上意味着開發人員可以定義子類,這些子類擁有其父類所擁有的所有屬性。直到 1976 年才被引入到面向對象編程中,也就是在其概念提出十年之後。

十年後,多態性才進入面向對象編程。由基本概念而言,多態性意味着一個方法或一個對象可以作爲其他方法或對象的模板。從某種意義上說,這是繼承的泛化,因爲並非原始方法或對象的所有屬性都需要傳輸到新實體;相反,你可以選擇重載屬性。

多態性的特殊之處在於,即使源代碼中兩個實體相互依賴,被調用的實體的工作方式也更像插件。這使得開發人員的工作更加輕鬆,因爲他們不必擔心運行時的依賴關係。

值得一提的是,繼承和多態性並不是面向對象編程所獨有的。真正的不同之處在於封裝數據片段和屬於它們的方法。在計算資源比今天稀缺的時代,這真的是一個天才的想法。

面向對象編程中的五大問題

面向對象編程一經問世,它就改變了開發人員看待代碼的方式。在 20 世紀 80 年代以前盛行的過程式編程,是非常面向機器的。開發人員需要對計算機如何工作有相當多的瞭解,才能寫出好代碼。

通過封裝數據和方法,面向對象編程使軟件開發更加以人爲本。它符合人類的直覺,方法drive()屬於數據組car,但不屬於組teddybear

繼承出現的時候,那也是直觀的。Hyundai汽車是car的一個子羣,有着相同的屬性,這是完全合理的,但PooTheBear卻並非如此。

這聽起來像是一臺強大的機器。然而,問題是,只知道面向對象編程的程序員會將這種思維方式強加於他們所做的每件事上。就像人們看到處都是釘子一樣,因爲他們只有一把錘子。正如我們將在下面看到的,當你的工具箱中只有一把錘子的時候,這可能會導致致命的問題。

香蕉大猩猩叢林問題

假設你正在設置一個新程序,並且你正在考慮設計一個新的類。然後,你回想起爲另一個項目創建的一個簡潔的小類,你意識到它對你目前正在嘗試做的事情來說是非常完美的。

沒問題!你可以在新項目中重用舊項目中的類。

除了這個類實際上可能是另一個類的子類外,所以現在還需要包含父類。然後,你意識到父類也依賴於其他類,如此一來,最終會包含大量的代碼。

Erlang 的創造者 Joe Armstrong 曾說過一句名言

面向對象編程的問題是,默認帶有環境。你只想要一個香蕉,但是得到了一隻拿着香蕉的大猩猩,甚至還有整個叢林。

這幾乎說明了一切。重用類是很好的做法。事實上,它可以成爲面向對象編程的一個主要優點。

但不要走極端。有時候,爲了避免 DRY(don’t repeat yourself 不要重複自己),你最好編寫一個新的類,而不是包含大量的依賴項。

脆弱的基類問題

假設你已經成功地爲新代碼重用了來自另一個項目的一個類。如果基類發生變化,會發生什麼情況?

它有可能會破壞你的整個代碼。甚至你可能連碰都沒有碰過。但是,有一天你的項目工作得很順利,但第二天就不這樣了,因爲有人更改了基類中的一個小細節,而這個細節最終對你的項目非常重要。

使用繼承的次數越多,可能需要進行的維護就越多。因此,儘管重用代碼在短期內看起來非常有效,但從長遠來看,它可能會付出高昂的代價。

鑽石問題

繼承是可愛的小東西,我們可以把一個類的屬性轉移給其他類。但如果你想混合兩個不同類的屬性呢?

嗯,你做不到。至少不會是以一種優雅的方式。例如,以類Copier爲例。(我從 Charles Scalfani 的文章《再見,面向對象編程》(Goodbye, Object Oriented Programming)中借用了這個例子,以及一些關於這裏提出的問題的信息)複印機掃描文檔內容並將其打印在控制上。那麼它應該是Scanner的子類,還是Printer的子類呢?

根本沒有好的答案。即使這個問題不會破壞你的代碼,它也會經常出現,令人沮喪。

層次問題

在鑽石問題中,問題是Copier是哪個類的子類。但我騙了你——因爲有一個很好的解決方案。假設Copier是父類,ScannerPrinter是僅繼承屬性子集的子類。問題解決!

這很好。但是,如果你的Copier只是黑白複印機,而你的Printer能處理彩色,那怎麼辦呢?從這個意義上說,Printer不就是Copier的泛化嗎?如果Printer連接到 WiFi,但Copier沒有連接,又該怎麼辦?

在類上堆積的屬性越多,建立適當的層次結構就越困難。實際上,你要處理的是一組屬性,其中Copier共享Printer的一些屬性,但不是所有屬性,反之亦然。如果你試圖將它固定到層次結構中,而你有一個龐大而複雜的項目,這可能會導致異常混亂的災難。

引用問題

你可能會說,好吧,那我們就只做面向對象的編程,不帶層次結構。相反,我們可以使用屬性集羣,並根據需要繼承、擴展或覆蓋屬性。當然,這可能會有點混亂,但它將是手頭問題的準確描述。

只有一個問題。封裝的全部意義在於保證數據片段之間的安全,從而使計算更加高效。如果沒有嚴格的層次結構,這是行不通的。

考慮如果一個對象A通過另一個對象B交互來覆蓋層次結構會發什麼。AB有什麼關係並不重要,重要的是B不是直接的父類。那麼A就必須包含對B的私有引用。否則,它將無法交互。

但是,如果A包含B的子類也擁有的信息,那麼這些信息就可以在多個地方被修改。因此,關於B的信息已不再安全,並且封裝也被破壞了。

儘管許多面向對象的程序員使用這種架構來構建程序,但這不是面向對象編程。只是一團糟。

單一範式的危險

這五個問題的共同之處在於,它們在不是最佳解決方案的地方實現了繼承。由於繼承甚至沒有包含在面向對象編程的原始形式中,我不會將這些問題稱爲面向對象的固有問題。它們只是一個教條走得太遠的例子。

但是,不僅僅是面向對象編程可能做過頭了。在純函數式編程中,在屏幕上處理用戶輸入或打印消息是極其困難的。對於這些目的,面向對象或過程化編程要更好一些。

儘管如此,仍有一些開發人員試圖將這些東西作爲純函數來實現,並將他們的代碼擴展到幾十行,以至於沒有人能夠理解。使用另一種範式,他們可以輕鬆地將代碼簡化爲幾行可讀的代碼。

範式有點像宗教。它們在適度的情況下是好的:可以說,耶穌、穆罕默德和佛陀都說過一些很酷的話。但是如果你跟隨他們到最後一個小細節,你可能最終會讓自己和周圍人們的生活變得相當悲慘。

編程範式也是如此。毫無疑問,函數式編程越來越受歡迎,而面向對象編程在過去幾年來受到了一些嚴厲的批評

瞭解新的編程範式並在適當的時候使用它們是有意義的。如果說,面向對象編程是讓開發人員無論走到哪裏都能看到釘子和錘子,那這是不是將錘子扔出窗外的理由呢?不是的。你可以在工具箱中添加一把螺絲刀,或者一把小刀、一把剪刀,然後根據手頭的問題來選擇工具。

函數式和麪向對象的程序員一樣,不要將你的範式當做宗教來對待。它們只是工具,都有自己的用途。你使用什麼工具應該只取決於你正在解決什麼問題。

最大問題是:我們是否正處於一場新革命的風口浪尖?

歸根結底,關於函數式編程與面向對象編程的爭論(不可否認,爭論是相當激烈的)歸結爲這樣一個問題:面向對象編程的時代會不會走到盡頭?

在函數式編程通常是更有效的選擇的情況下,出現了越來越多的問題。請想一想數據分析、機器學習和並行編程。你越是深入這些領域,就會越喜歡函數式編程。

但是如果你看一下現狀,面向對象的程序員有很多工作機會,而函數式程序員只有寥寥可數的工作機會。這並不意味着如果你喜歡後者就找不到工作;現在函數式開發人員仍然相當稀缺。

最有可能的情況是,面向對象編程將再持續十年左右。當然,先鋒派是函數式編程,但這並不意味着你應該拋棄面向對象編程。面向對象編程仍然是令人難以置信的好東西。

因此,在接下來的幾年,不要將面向對象編程從你的工具箱扔出去。但要確保它不是你唯一的工具。

作者介紹:

Rhea Moutafis,正在攻讀暗物質物理學博士學位。熱愛藝術、音樂及美好事物。

原文鏈接:

https://towardsdatascience.com/object-oriented-programming-is-dead-wait-really-db1f1f05cc44

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