面向對象程序設計大行其道幾十年後,已經在面臨淘汰?

2020-10-27 讀芯術

全文共3838字,預計學習時長10分鐘


圖源:unsplash


編程在上世紀60年代遇到了一個大問題:計算機那時還沒有那麼強大,需要以某種方式在數據結構和進程之間分配容量。這意味著如果擁有大量數據,那麼在不將計算機推向極限的情況下,很多事情將無法完成。另一方面,如果需要做很多事情,那麼就不能使用過多的數據,否則計算機將永遠佔據空間。


接著艾倫·凱(AlanKay)大約於1966年或1967年得出理論認為可以使用封裝的微型計算機,這些微型計算機不共享數據,而是通過消息傳遞進行通信。這樣可以更加經濟地使用計算資源。


儘管這個想法很巧妙,但直到1981年,面向對象編程才成為主流。但是從那以後,它並沒有停止吸引軟體開發新手和老手。面向對象編程的程式設計師一如既往的繁忙。


但近年來,這一已有十年歷史的範式受到越來越多的批評。難道是在面向對象程序設計大行其道40年之後,技術已經超越了這種範式?


帶數據的耦合函數是否可笑?


面向對象編程的主要思想非常簡單:嘗試將一個程序分解為功能強大的整體。隨之而來的是,將數據片段和僅在相關數據上使用的那些函數耦合在一起。


請注意,這僅涵蓋封裝的概念。也就是說,位於對象內部的數據和函數對於外部是不可見的,一個人只能通過消息(通常稱為getter和setter函數)與對象的內容進行交互。


繼承和多態並沒有包含在最初的想法中,但是對於當今的面向對象編程而言,這是必需的。繼承基本上意味著開發人員可以定義具有其父類具有的所有屬性的子類,直到1976年——面向對象的程序設計概念問世十年後,才將其引入。


十年後,多態進入了面向對象的程序設計。從根本上講,這意味著方法或對象可以用作其他方法的模板。從某種意義上說,這是繼承的概括,因為並非原始方法或對象的所有屬性都需要傳輸給新實體;相反,可以選擇覆蓋屬性。


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


值得一提的是,繼承和多態性並不是面向對象編程所獨有的。真正的區別在於封裝數據及其所屬的方法。在那個計算資源比今天稀缺得多的時代,這是一個天才般的想法。面向對象的編程並不可笑,它使編碼變得容易得多。


圖源:unsplash


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


面向對象編程一問世便改變了開發人員查看代碼的方式。在1980年代以前,面向過程編程通常以機器為中心,開發人員需要非常了解計算機如何工作才能編寫好的代碼。


通過封裝數據和方法,面向對象的編程使軟體開發更加以人為中心。與人類的直覺相符,方法drive()屬於數據組 car,但不屬於teddybear組。當繼承產生時,這也很直觀。Hyundai是car的一個子類,並且具有相同的屬性,但PooTheBear卻不是,這是完全合理的。


這聽起來像是一臺強大的機器。但問題在於,只懂面向對象代碼的程式設計師將會用這種思維方式思考他們所做的一切。就像人們到處看到釘子一樣,因為他們只有錘子。正如我們將在下面看到的那樣,當你的工具箱只有錘子時,可能會導致致命的問題。


大猩猩叢林香蕉問題


如果你正在設置一個新程序,並且正在考慮設計一個新類。你可能會回想起為另一個項目創建的簡潔的小類,並且意識到這對當前正在嘗試的工作非常適合。沒問題!可以將舊項目中的類重用於新項目。


除了該類實際上可能是另一個類的子類之外,因此現在還需要把父類包括在內。然後你意識到父類也依賴於其他類,並且最終包含了代碼堆。


Erlang的創建者Joe Armstrong的這句話非常著名:「面向對象程式語言的問題在於,它們具有隨身攜帶的所有隱式環境。你想要香蕉,但是得到的是一隻拿著香蕉的大猩猩和整個叢林。」


這對此方法進行了很好的說明。可以重用類,實際上,這可能是面向對象編程的主要優點。但不要走極端,有時最好編寫一個新類,而不是為了寫重複代碼而添加大量依賴項。要靈活變通,不要死板地遵從某個範式。


圖源:unsplash


脆弱的基類問題


如果已經成功地將另一個項目中的類重用於新代碼,那麼基類會發生怎樣的變化?


它可能會破壞整個代碼,而你甚至可能都沒有碰過它。也許有一天你手上的項目熠熠生輝,而第二天卻被打回原形,因為有人更改了基類中的一個細微細節,而該細節最終對項目至關重要。


使用繼承的次數越多,潛在的維護工作就越多。因此,即使在短期內重用代碼似乎非常有效,但從長遠來看,它可能會帶來很大的代價。


鑽石問題


繼承是一件可愛的小事,可以在其中繼承一類的屬性並將其轉移給其他類。但該如何組合兩個不同類的屬性?


這也許做不到,至少沒辦法以簡潔的方式做到,例如Copier類。(筆者從Charles Scalfani的熱門文章《再見,面向對象的編程》中借用了這個示例以及有關此處出現的問題的一些信息。)複印機掃描文檔的內容並將其列印在空白紙上,它應該是Scanner還是Printer的子類?


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


層次問題


在鑽石問題中,問的是Copier是哪個類的子類。但其實我話沒說完,有一個簡單的解決方案。假設Copier 是父類,而Scanner 和Printer是僅繼承屬性子集的子類。


這就變得很簡單。但如果Copier只是黑白複印,而Printer還可以彩色列印怎麼辦?從這個意義上說,印表機不是包括複印機的嗎?如果印表機連接到WiFi但複印機沒有連接怎麼辦?


在類上堆積的屬性越多,建立適當的層次結構就越困難。確實,在處理屬性集群時,其中Copier共享了Printer的部分但不是全部屬性,反之亦然。而且,如果嘗試將其置於層次結構中,並且是一個大型複雜項目,則可能會導致混亂。不要混淆層次結構,否則可能會陷入混亂。


圖源:unsplash


參考問題


有人也許會說那麼我們將進行沒有層次結構的面向對象編程。其實相反,我們可以使用屬性集群,並根據需要繼承、擴展或覆蓋屬性。這會有些混亂,但這將是對當前問題的準確表現。


還有一個問題。封裝的全部目的是使數據片段彼此之間保持安全,從而使計算效率更高。沒有嚴格的層次結構,這是行不通的。


如果一個對象A通過與另一個對象B交互來覆蓋層次結構,會發生什麼?A與B的關係並不重要,除了B不是直接的父類。然後,A必須包含對B的私有引用,否則,將無法交互。但是,如果A包含B的子代也具有的信息,則可以在多個位置修改該信息。因此,有關B的信息已不再安全,並且封裝被破壞。


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


單一範式的危險


這五個問題的共同點是它們在不是最佳解決方案的地方實現了繼承。由於繼承甚至沒有包含在面向對象編程的原始形式中,因此筆者不會將這些問題稱為面向對象固有的問題,它們只是太過教條式的例子。


但是,不僅面向對象的編程可能會被誇大。在純函數式編程中,處理用戶輸入或在屏幕上列印消息極為困難。出於這些目的,面向對象或過程編程要好得多。


仍然有一些開發人員嘗試將這些東西實現為純函數,並將其代碼分解為數十行,沒人能理解。使用另一種範式,他們可以輕鬆地將代碼簡化為幾行可讀的代碼。


範式有點像宗教,它們都具有一定的合理性,耶穌、穆罕默德和佛陀說了一些很酷的話。但是,如果一直遵循教條,可能最終會使自己和周圍人的生活痛苦不堪。編程範式也是如此。毫無疑問,函數式編程正逐漸受到人們的歡迎,而在過去的幾年中,面向對象的編程遭到了一些嚴厲的批評。


了解新的編程範式並在適當的時候使用它們是有意義的。如果面向對象編程是使開發人員無論走到哪裡都能看到釘子的錘子,那是把錘子扔出窗戶的原因嗎?不是。你在工具箱中添加了一把螺絲刀,也許是一把刀或一把剪刀,你不過是根據當前問題選擇工具。


函數式編程和面向對象編程的程式設計師都不要像對待宗教那樣對待編程範式。它們是工具,都可以在某處使用,所使用的內容僅取決於待解決的問題。


一個大問題:我們正處於一場新革命的風口浪尖上嗎?


圖源:unsplash


歸根結底,關於函數式編程和面向對象編程的爭論(相當激烈)可以歸結為這一點:是否可以邁入面向對象編程時代的盡頭?


函數式編程通常是更有效的選擇,越來越多的問題出現。如數據分析、機器學習和並行編程,對這些領域的投入越多,就會越喜歡函數式編程。但看看現狀,有十多種面向對象編程的程式設計師提供的產品,還有一種針對函數式編碼器的產品。這並不意味著你不會喜歡這份工作,如今,函數式編程開發人員仍然非常稀缺。


最有可能的情況是,面向對象的編程將繼續存在十年左右。函數式編程當然會越來越受歡迎,但這並不意味著應該放棄面向對象編程。把面向對象編程作為保留技能仍然非常有優勢。


因此,在接下來的幾年中,不要將面向對象的編程丟到工具箱外,但是請確保它不是你唯一的工具。



留言點讚關注

我們一起分享AI學習與發展的乾貨

如轉載,請後臺留言,遵守轉載規範

相關焦點

  • 科普文,面向對象程序設計,要知道的那點事
    面向對象程序設計更簡單,編程者需要關心的事情,就那點事。一、什麼是對象?在現實生活中,每一個具體事物,都是對象!在程序設計中,每一個可以操作的實體,就是對象。是具有屬性和方法的實體。舉個例子吧!表單、標籤、命令按鈕都是對象。二、什麼是對象的屬性和屬性值?在現實生活中,每個對象都有自己的特性,我們可以具現化成一個具體的值。某喵,體重2斤,梨花毛,出生日期2020年8月4日。在面向對象程序設計中,對象的特性稱為對象的屬性。對象特性的具體值,被稱為屬性值。比如,程式設計師可以給不同的命令按鈕,賦予不同的屬性值。
  • 如何面向對象軟體設計?
    軟體設計也分大小,每個軟體開發工程師都有自己的設計,下面談談自己的見解 軟體開發的相關技術更新快,不到幾年時間之前掌握的框架等技術都逐漸被淘汰,有些技術升級成新的技術仍在使用。 技術是第一生產率。技術更新是為了更快提高開發效率,讓開發者更多時間用於業務開發。 第一代微服務架構才過多久,第二代微服務架構service Mesh已經登場。
  • JavaScript面向對象篇
    而今天Web2.0的時代,Ajax大行其道,很多複雜的腳本成為其必須的組成部分。在Ajax應用中利用JavaScript面向對象編程風格,能夠使邏輯更加清晰,也更有利於問題的解決。如果你想用JavaScript編寫一個庫,比如ExtJS或者YUI,很難想像你的類庫不使用面向對象的編程風格——否則的話,無論是對你還是對使用者的智力都將是一個前所未有的考驗!
  • 是時候讓 JavaScript 面向對象了!
    「經驗豐富的後臺開發總是瞧不上前端的技術,尤其是 JavaScript,一直被當作不入流的語言」,雖然在幾十年前,JavaScript 只能開發非常小且功能單一的應用程式,但如今無論是前端還是後端,JavaScript 在規模和複雜性方面都取得了很大的發展。而 JavaScript 中的面向對象則有助於減輕心理負擔,並避免基於函數的編程中固有的紛雜的關係。
  • 面向對象設計與統一建模語言UML
    面向對象設計自從面向對象程式語言在軟體開發中成為主流之後,遵循面向對象技術特點的軟體設計工作,也一併發展了起來。最後會以一個示例講述在面向對象設計中,如何應用UML來完成建模工作。我們進行面向對象的設計工作,終歸是要讓計算機來幫助我們處理那些繁瑣、重複性的工作。那麼,接下來我們就以一個租車業務為示例,使用UML工具進行設計過程吧。
  • 面向對象編程的災難:是時候考慮更新換代了!
    圖片來源:Unsplash/MuukiiAlan Kay的想法是讓獨立的程序(細胞)通過相互發送消息進行通信。獨立程序的狀態永遠不會與外部世界共享(封裝)。面向對象編程從來沒有打算擁有諸如繼承、多態性、「new」關鍵字和無數設計模式之類的東西。最純粹的面向對象編程設計Erlang是面向對象編程最純粹的形式。
  • javascript自學記錄:面向對象程序設計1
    PS:javascript的面向對象跟其他程序不一樣,書中剛一開始就很難,容易讓人從入門到放棄。個人總結的經驗是:對於不容易明白的東西,有代碼就照著敲代碼,敲一遍可能會有收穫;實在不明白的,糾結也沒用,先跳過。
  • 軟體項目實訓及課程設計指導——如何實現面向對象的系統架構設計
    因此,在軟體應用系統的設計、開發實現中應該要綜合應用面向對象(OOP)的編程技術和面向方面(AOP)的編程技術。在如下示圖中的程序代碼中夾雜有大量的日誌功能實現的程序代碼,導致日誌功能實現的程序代碼水平地散布在所有對象的層次中----在控制層、業務層和數據訪問層都需要這樣的日誌功能實現,並且而與它所散布到的對象的核心功能毫無關係。
  • 如何以面向對象的思想設計有限狀態機
    問題背景為了更好地描述狀態機的應用,這裡用一個地鐵站的閘機為背景,簡單敘述一下閘機的工作流程:通常閘機默認是關閉的,當閘機檢測到有效的卡片信息後,打開閘機,當乘客通過後,關閉閘機;如果有人非法通過,那麼閘機就會產生報警,如果閘機已經打開,而乘客仍然在刷卡,那麼閘機將會顯示票價和餘額,
  • 設計模式之面向對象編程六大原則
    我常常將面向對象六大原則想像為程式設計師的上層內功心法,而將設計模式看作是程式設計師的一套武功招式。如果你的內功心法理解到位,在軟體開發過程中,很可能不自覺的使用了很多設計模式而不自知。面向對象編程的三個基本特性首先,我們先回顧一下面向對象編程的三個基本特性:封裝繼承多態在應用開發過程中,最難的不是完成應用的開發工作,而是在後續的升級、維護過程中讓應用系統能夠擁抱變化。
  • 面向對象編程會被拋棄嗎?這五大問題不容忽視
    面向對象的程式設計師市場一如既往地忙碌。但是在最近幾年中,這種已有幾十年歷史的編程範式受到越來越多的批評。難道是在面向對象編程大行其道 40 年之後,技術已經超越了這種範式?也就是說,位於對象內部的數據和函數對於外部是不可見的。我們只能通過消息(通常通過 getter 和 setter 函數)與對象的內容進行交互。繼承性和多態性並沒有包含在最初的設計想法中,但是對於現在的面向對象編程而言是必需的。繼承基本上意味著開發者可以定義具有其父類所有屬性的子類。
  • 初識Python面向對象
    面向對象or面向過程面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作為程序的基本單 元,一個對象包含了數據和操作數據的函數。面向過程的程序設計把電腦程式視為一系列的命令集合,即一組函數的順序執行。
  • UML - 面向對象還是面向過程
    我對面向對象編程的目標從就就不是復用。相反,對我i來說,對象提供了一種處理複雜性問題的方式。這個問題可以追溯到亞里斯多德:您把這個世界視為過程還是對象?早面向對象興起運動之前,編程以過程為中心,例如結構化設計方法。然而,系統已經到達了超越其處理能力的複雜性極點。
  • 深入淺出理解面向過程與面向對象編程
    面向過程會要求去掌控每一個細節,而面向對象則只需要挑選合適的工具即可。為了簡化工作我需要計算機來計算數據,並且我還希望程序能夠顯示這些數據,那麼我應該如何做呢?我可能會想到調用函數來完成輸入的工作,調用另外一個函數完成計算的工作,然後調用第三個函數完成顯示的工作。那麼,獲得下一場比賽的數據後,又應該怎麼做呢?我可不想再從頭開始了,這時候我會選擇調用一個更新數據的函數。在這些基礎上,我會想做一個菜單,選擇是輸入、計算、顯示還是更新。那麼這些數據如何存儲呢?
  • 面向對象的兩大迷思,再給你們解答一次
    用C語言一樣可以寫出面向對象的程序,用Java也可以寫出面向過程的程序。我們以Redis為例。Redis是標準的C語言程序,但是你知道嗎,其中就用到了面向對象的思想。nbsp; //此處省略具體實現    }}面向對象經過幾十年的發展
  • Objeck v5.6.1 發布,面向對象程序設計語言 - OSCHINA - 中文開源...
    Objeck 是一種受 Java 啟發,同時受 Scheme 和 UML 影響的面向對象程序設計語言。Objeck 特性為快速,易於使用,輕巧且跨平臺。Objeck 把所有的數據類型都當成是對象,包含一個編譯器和虛擬機,具有內存管理和 JIT 編譯器。
  • 面向對象的產品觀(5):具象化
    互動設計已經是一門經過了幾十年發展的顯學,在這裡我一篇文章也不可能說明白所有的要素。所以,今天我就說到這裡,權當拋磚引玉,如果讀者們還有興趣,可以自行查閱相關的文獻,我就不在多囉嗦了。三、信息架構:我們想告知用戶什麼與互動設計對應的就是信息架構,他與互動設計相輔相成,共同構成了產品的具象層。
  • Python面向對象編程的基本概念
    由九道門商業數據分析學院提供介紹在學習面向對象的編程時。我決定深入了解它的歷史,結果令人著迷。術語「面向對象程序設計」(OOP)是艾倫·凱(Alan Kay)在1966年讀研究生時提出的。名為Simula的語言是第一種具有面向對象編程功能的程式語言。它是在1967年開發的,用於製作仿真程序,其中最重要的信息稱為對象。
  • 詳解Python面向對象知識點
    目前代碼技能已經成了測試同學面試考核的剛需,對於測試開發來講需求最大的是java和python兩門語言,二者也都是面向對象語言。對於剛入門代碼的同學來說面向對象相關的概念比較難於理解,而面向對象編程相關的知識點偏偏又是面試中的高頻問題,所以本文我以python為例,帶大家快速搞定面向對象中的核心概念並通過代碼實現的方式來幫助大家對其加深理解!
  • 面向對象的工業編程(OOIP)
    這就是為什麼圖形語言一直是工業控制程序設計的主體,並且工業控制工程師傾向於在採用之前使計算機科學的最新趨勢成熟的原因(例如符號尋址和數據結構在進入工業控制之前都已經成熟了20年)更多信息盡在振工鏈。面向對象編程(OOP)在1990年代開始被計算機科學家使用,但是由於它的複雜性和缺乏支持的圖形語言環境,在工業控制領域的應用一直很緩慢。幸運的是,工業軟體供應商已經開始解決這些問題,並向控制項世界提供了OOP的許多好處,而沒有任何複雜性。