面向物件編程的時代會不會走到盡頭?
在 20 世紀 60 年代,編程有一個很大的問題:計算機還遠沒有那么強大,而且不知何故,它們還需要在資料結構和程序之間以某種方式分配容量,
這意味著,如果你有大量資料的話,你就不能用它做那么多的事情,否則就會把計算機逼到極限,而另一方面,如果你需要做很多事情,你就不能使用太多的資料,否則計算機將會耗費大量時間,
后來,Alan Lay 在 1966 年或 1967 年提出了一個理論,即人們可以使用封裝起來的微型計算機,這種計算機并不共享資料,而是通過訊息傳遞并進行通信,通過這種方式,可以做到更經濟地使用計算資源,
盡管這個想法很有創意,但 直到 1981 年,面向物件編程才成為主流,然而,從那時起,它就一直吸引著新入門的和經驗豐富的軟體開發人員,面向物件的程式員市場一如既往地繁忙,
但近年來,這一有著十年歷史的范式受到了越來越多的批評,有沒有可能,在面向物件編程普及四十年后,技術已經超越了這種方式?

耦合函式與資料有那么“愚蠢” 嗎?
面向物件編程背后的主要思想非常簡單:試圖將一個程式分解成與整體一樣強大的部分,接下來,你需要將資料片段和那些僅在相關資料上使用的函式耦合在一起,
請注意,這僅僅只是涵蓋了封裝的概念,也就是說,位于物件內部的資料和函式對外部都是不可見的,人們只能通過訊息與物件的內容進行互動,通常稱為getter和setter函式,
最初的想法中沒有包含的,但被認為是當今面向物件編程必不可少的是:繼承和多型性,
繼承基本上意味著開發人員可以定義子類,這些子類擁有其父類所擁有的所有屬性,直到 1976 年才被引入到面向物件編程中,也就是在其概念提出十年之后,
又十年后,多型性才進入面向物件編程,由基本概念而言,多型性意味著一個方法或一個物件可以作為其他方法或物件的模板,從某種意義上說,這是繼承的泛化,因為并非原始方法或物件的所有屬性都需要傳輸到新物體;相反,你可以選擇多載屬性,
多型性的特殊之處在于,即使源代碼中兩個物體相互依賴,被呼叫的物體的作業方式也更像插件,這使得開發人員的作業更加輕松,因為他們不必擔心運行時的依賴關系,
值得一提的是,繼承和多型性并不是面向物件編程所獨有的,真正的不同之處在于封裝資料片段和屬于它們的方法,在計算資源比今天稀缺的時代,這真的是一個天才的想法,

面向物件編程中的五大問題
面向物件編程一經問世,它就改變了開發人員看待代碼的方式,在 20 世紀 80 年代以前盛行的程序式編程,是非常面向機器的,開發人員需要對計算機如何作業有相當多的了解,才能寫出好代碼,
通過封裝資料和方法,面向物件編程使軟體開發更加以人為本,它符合人類的直覺,方法 drive() 屬于資料組 car,但不屬于組 teddybear,
繼承出現的時候,那也是直觀的,Hyundai汽車是car的一個子群,有著相同的屬性,這是完全合理的,但PooTheBear卻并非如此,
這聽起來像是一臺強大的機器,然而,問題是,只知道面向物件編程的程式員會將這種思維方式強加于他們所做的每件事上,
就像人們看到處都是釘子一樣,因為他們只有一把錘子,正如我們將在下面看到的,當你的工具箱中只有一把錘子的時候,這可能會導致致命的問題,
? 一、香蕉大猩猩叢林問題
假設你正在設定一個新程式,并且你正在考慮設計一個新的類,然后,你回想起為另一個專案創建的一個簡潔的小類,你意識到它對你目前正在嘗試做的事情來說是非常完美的,
沒問題!你可以在新專案中重用舊專案中的類,
除了這個類實際上可能是另一個類的子類外,所以現在還需要包含父類,然后,你意識到父類也依賴于其他類,如此一來,最侄訓包含大量的代碼,
Erlang 的創造者 Joe Armstrong 曾說過一句 名言:
面向物件編程的問題是,默認帶有環境,你只想要一個香蕉,但是得到了一只拿著香蕉的大猩猩,甚至還有整個叢林,
這幾乎說明了一切,重用類是很好的做法,事實上,它可以成為面向物件編程的一個主要優點,
但不要走極端,有時候,為了避免 DRY(don’t repeat yourself 不要重復自己),你最好撰寫一個新的類,而不是包含大量的依賴項,
? 二、脆弱的基類問題
假設你已經成功地為新代碼重用了來自另一個專案的一個類,如果基類發生變化,會發生什么情況?
它有可能會破壞你的整個代碼,甚至你可能連碰都沒有碰過,
但是,有一天你的專案作業得很順利,但第二天就不這樣了,因為有人更改了基類中的一個小細節,而這個細節最終對你的專案非常重要,
使用繼承的次數越多,可能需要進行的維護就越多,因此,盡管重用代碼在短期內看起來非常有效,但從長遠來看,它可能會付出高昂的代價,
? 三、鉆石問題
繼承是可愛的小東西,我們可以把一個類的屬性轉移給其他類,但如果你想混合兩個不同類的屬性呢?
嗯,你做不到,至少不會是以一種優雅的方式,
例如,以類Copier為例,(我從 Charles Scalfani 的文章)中借用了這個例子,以及一些關于這里提出的問題的資訊)復印機掃描檔案內容并將其列印在控制上,那么它應該是Scanner的子類,還是Printer的子類呢?
根本沒有好的答案,即使這個問題不會破壞你的代碼,它也會經常出現,令人沮喪,
? 四、層次問題
在鉆石問題中,問題是 Copier 是哪個類的子類,但我騙了你——因為有一個很好的解決方案,假設 Copier 是父類,Scanner 和 Printer 是僅繼承屬性子集的子類,問題解決!
這很好,但是,如果你的Copier只是黑白復印機,而你的Printer能處理彩色,那怎么辦呢?
從這個意義上說,Printer不就是Copier的泛化嗎?如果Printer連接到 WiFi,但Copier沒有連接,又該怎么辦?
在類上堆積的屬性越多,建立適當的層次結構就越困難,實際上,你要處理的是一組屬性,其中Copier共享Printer的一些屬性,但不是所有屬性,反之亦然,
如果你試圖將它固定到層次結構中,而你有一個龐大而復雜的專案,這可能會導致例外混亂的災難,
? 五、參考問題
你可能會說,好吧,那我們就只做面向物件的編程,不帶層次結構,
相反,我們可以使用屬性集群,并根據需要繼承、擴展或覆寫屬性,當然,這可能會有點混亂,但它將是手頭問題的準確描述,
只有一個問題,封裝的全部意義在于保證資料片段之間的安全,從而使計算更加高效,如果沒有嚴格的層次結構,這是行不通的,
考慮如果一個物件A通過另一個物件B互動來覆寫層次結構會發什么,A與B有什么關系并不重要,重要的是B不是直接的父類,那么A就必須包含對B的私有參考,否則,它將無法互動,
但是,如果A包含B的子類也擁有的資訊,那么這些資訊就可以在多個地方被修改,因此,關于B的資訊已不再安全,并且封裝也被破壞了,
盡管許多面向物件的程式員使用這種架構來構建程式,但這不是面向物件編程,只是一團糟,

單一范式的危險
這五個問題的共同之處在于,它們在不是最佳解決方案的地方實作了繼承,
由于繼承甚至沒有包含在面向物件編程的原始形式中,我不會將這些問題稱為面向物件的固有問題,它們只是一個教條走得太遠的例子,
但是,不僅僅是面向物件編程可能做過頭了,在純 函式式編程 中,在螢屏上處理用戶輸入或列印訊息是極其困難的,對于這些目的,面向物件或程序化編程要更好一些,
盡管如此,仍有一些開發人員試圖將這些東西作為純函式來實作,并將他們的代碼擴展到幾十行,以至于沒有人能夠理解,使用另一種范式,他們可以輕松地將代碼簡化為幾行可讀的代碼,
范式有點像宗教,它們在適度的情況下是好的:可以說,耶穌、穆罕默德和佛陀都說過一些很酷的話,但是如果你跟隨他們到最后一個小細節,你可能最侄訓讓自己和周圍人們的生活變得相當悲慘,
編程范式也是如此,毫無疑問,函式式編程 越來越受歡迎,而面向物件編程在過去幾年來受到了一些 嚴厲的批評,
了解新的編程范式并在適當的時候使用它們是有意義的,
如果說,面向物件編程是讓開發人員無論走到哪里都能看到釘子和錘子,那這是不是將錘子扔出窗外的理由呢?不是的,你可以在工具箱中添加一把螺絲刀,或者一把小刀、一把剪刀,然后根據手頭的問題來選擇工具,
函式式和面向物件的程式員一樣,不要將你的范式當做宗教來對待,它們只是工具,都有自己的用途,你使用什么工具應該只取決于你正在解決什么問題,

我們是否正處于一場新革命的風口浪尖?
歸根結底,關于函式式編程與面向物件編程的爭論(不可否認,爭論是相當激烈的)歸結為這樣一個問題:面向物件編程的時代會不會走到盡頭?
在函式式編程通常是更有效的選擇的情況下,出現了越來越多的問題,請想一想資料分析、機器學習和并行編程,你越是深入這些領域,就會越喜歡函式式編程,
但是如果你看一下現狀,面向物件的程式員有很多作業機會,而函式式程式員只有寥寥可數的作業機會,這并不意味著如果你喜歡后者就找不到作業;現在函式式開發人員仍然相當稀缺,
最有可能的情況是,面向物件編程將再持續十年左右,當然,先鋒派是函式式編程,但這并不意味著你應該拋棄面向物件編程,面向物件編程仍然是令人難以置信的好東西,
因此,在接下來的幾年,不要將面向物件編程從你的工具箱扔出去,但要確保它不是你唯一的工具,

不管你是轉行也好,初學也罷,進階也可——【值得點擊進入】的程式員編程俱樂部!
涉及到:C語言、C++、windows編程、網路編程、QT界面開發、Linux編程、游戲編程、黑客等等......

編程入門資料:

?推薦學習書籍:

一個活躍、高逼格、高層次的程式員編程學習殿堂;編程入門只是順帶,思維的提高才有價值!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/201747.html
標籤:其他
