如何形式化定義「什麼是面向對象」?
網上的好多有關面向對象的描述,都讓人摸不著頭腦。特別是很多人把面向對象和過程式編程由包含關係誤解為對立關係了,有的人把封裝當做面向對象了(比如說,函數和數據是否在一個命名空間內),還有的人把自己語言里的特性當做面向對象的準則了,還有的人把參數位置的替換也當做面向對象的準則了(從 f(o,arg1,arg2)換成o.f(arg1,arg2))。
對於面向對象,現在有沒有標準的,形式化的定義呢?
引一下以前的回答,原問題是"java語言以什麼底層模型為基礎?"
推薦兩個比較經典的:
Featherweight Java(FJ)
Middlleweiht Java(MJ)以及兩本書A theory of objectsFoundations of object-oriented languages FJ還是挺簡單的, 用PLT Redex/Coq/Agda/.. 可以比較快地實現,有興趣的的學可以玩玩什麼「底層模型」沒有統一的答案,看具體需求,比如要建模concurrency,可能用到mu calculus/Concurrent kleene algebra/concurrent SL...,想實現指稱語義的full abstraction,可能通過Game semantic,很多博弈論和範疇論的東西...等等..題外話,這些和是否做OOP無關,首先做OOP的都不一定關心這些,然後大家看:FJ作者是Benjamin Pirece和Philip Wadler(哪裡不對..)..
題主確定要形式化的定義????OOP這個東西好笑就好笑在我大概形容下他什麼意思很容易,但是真的用PL theory寫出來就很蛋疼了。因為這個東西本身就是個工程學概念,源於人類平時思考的方式,而不源於數學。
數學上大致的思路是,形式化定義OOP的各種關鍵特性,比如通過dispatch matrix實現多態,通過signature實現分類,等等。也就是說,形式化定義只有更難理解,沒有相應的基礎大概要讀個一年書。具體更加複雜等回家我翻翻書再說。面向對象本身就不是一個formal 的定義。
另外這個面向對象的神翻譯簡直就是誤人子弟。Object Oriented 根對象一毛錢關係都沒有。台灣人翻譯的「以物件(構件)為導向」,就精確也好理解得多,基本上不需要解釋就可以理解。[如果覺得不好理解的話,可以類比一下 「以社會主義核心價值觀為導向加強社區文化建設」,分分鐘明白。]
這裡的物體就是現實中的物體的意思。
放到編程領域,就是要讓你通過構建有不同功用的物件,然後把他們有效的組合在一起來解決問題。
因為其整個思維方式和現實比較接近,理解起來比較intuitive,用好了解決問題能力也很強,所以就漸漸流行起來了。另外,OO的思想和Functional 並不衝突。和Functional衝突的是Procedural。
而OO的思想在兩個paradigm 里都可以使用。
如果一個語言的編譯器提供一個可以把函數的第一個參數寫在函數名前面的語法糖,那麼就這個語言就可以叫面向對象語言。
OO這個東西,一個語法糖一個虛函數表,跟本沒必要大吹特吹。現在每本教材都高喊著「封裝、繼承、多態」的口號,以為這些東西是OO帶來的特性,就完全屬於著了概念販子的道了。
真要嚴格的形式化定義恐怕要從底層機器語言出發了。
計算機中的面向對象要符合其對應的層次。不考慮數據本身,而是考慮數據所代表的對象的行為。
===以下偏題===
因此,POJO不是對象(只是數據的合集,本身沒有真正意義的「行為」,靜態類也不是對象(類名只是面向過程的命名空間而已)。
把第一個形參變成點前面的對象只是一種形式。如果語言不支持這種寫法,那麼當作第一個參數也是恰當的。(例如在C里實現面向對象)。
多態什麼的同理,我完全可以在結構體里開一個欄位用於存放某個方法的處理函數的指針。
C++不被認為是純粹的面向對象語言的原因除了全局函數之外,還有原生類型不是對象,沒有自身的行為這一點。
所以,這麼說來其實Java也不完全是面向對象的(畢竟不能直接5.ToString()啊233)
鴨子類型是面向對象,因為相比繼承和多態,鴨子類型只考慮謂語本身,而不考慮其含義。至於你會不會寫錯方法名,誰TM管你。
最後就是,面向對象不是萬能的。以上。
通過使用抽象數據類型(對使用者隱藏細節),來提高代碼的可靠性和可復用性。
推薦閱讀:
※【Kotlin填坑-03】類訪問器get和set :不要自己調用自己啊!
※這樣理解面向對象的封裝,繼承,多態是否正確?
※如何理解「在面向對象編程的時候,方法或者函數的參數最好是介面或者抽象類」?
※封裝和抽象的區別是什麼?
