物件導向與函式程式設計的比較

banq發表於2014-11-26
最近Bob大叔發表了OO vs FP博文,文章推崇物件導向與函式程式設計融合。大意翻譯如下:

一個朋友在Facebook釋出如下一個對比,這激怒了我,如下圖:

[img index=1]

有很多程式設計師說過類似的事情, 他們認為物件導向和函數語言程式設計是互斥形式的程式設計。 函式程式設計狂熱分子好像是象牙塔的高等生命看不起地上窮且天真的OO程式設計師。而OO程式設計師也類似一樣指責函式語言中括號汙染和浪費。

這些觀點都是基於OO與FP的無知。

首先要強調幾點:
1. OO不是關於狀態

物件不是資料結構,物件可能使用資料結構,但是這些資料結構使用方式是隱藏的,這就是為什麼資料欄位是私有的原因,從物件外部看,你看不見任何狀態,所有你看到的都是函式方法,這樣物件也是關於函式方法的,不是關於狀態。

當物件用作資料結構時,它是一種設計風格,比如Hibernate自稱自己是物件-關聯式資料庫的對映,其實不正確,ORM並不是關聯式資料庫和物件的對映,而是關聯式資料庫和資料結構的對映,這些資料結構並不是物件。

物件是一包函式,不是一包資料。

2.函式程式設計類似OOP是由運算元據的函式組成。
每個函式程式設計程式都是由運算元據的一系列的函式組成,每個OO程式也是由一系列運算元據的函式組成。

對於OO程式設計師將函式和資料定義在一起,事實上,所有程式都是函式繫結到資料。

你也許認為這裡繫結的方式還是有區別的,但是仔細想想這是很愚蠢的,難道 f(o), o.f(), 和 (f o)有區別嗎?難道區別真的是函式呼叫語法不同嗎?

區別
那麼OO與 FP的區別是什麼?什麼是OO有但是FP不能做的,而FP能做的OO則不能的?

1. FP規定了分配的紀律
真正函式程式設計並沒有分配符號,你不能改變變數的狀態,確實,變數這個詞語在函式程式設計中屬於用詞不當,你其實不能改變它們。

函式程式設計經常會說函式是第一等公民,smalltalk確實是將函式作為一等公民,但是small talk是面嚮物件語言,不是函式語言。

函式語言與非函式語言的區別是函式語言並不分配statement。

這意味著在函式語言中從來不能改變狀態嗎?不是,函式語言通常提供某種方式讓你改變狀態, F允許你定於“可變變數”,Clojure允許你建立一個特殊物件,其狀態可以透過魔術的咒語來改變。

關鍵是一種函式式語言對變化狀態透過強加某種儀式施以紀律。 你必須透過正確的方式去做。

2. OO強加函式指標的約束
一些人認為物件是真實世界的物件對映,這樣OOP更加貼近我們的思考方式,其實OO真正特點是使用方便的多型性替代了函式指標。

如何實現多型?使用函式指標實現, OO語言簡化這種實現,隱藏了函式指標,因為函式指標難以管理得很好,因此這點無疑是值得肯定的,試圖使用函式指標如C編寫一個多多型程式碼看看?它們會有複雜不方便的約定,需要遵循“每種情況下”,這通常不現實的。

在Java中,你呼叫的每個函式都是多型的,你沒有辦法呼叫不是多型的函式,那就意味著每個java函式間接地透過函式指標被呼叫。

如果你需要在C中使用多型,你得自己管理這些指標,這很難,如果你想在Lisp中使用多型性,你也得自己管理指標,將它們作為引數傳送到高階演算法(這是一種策略模式),但是在OO語言中,這些指標語言已經幫助你管理,語言會初始化它們 轉換marshal 它們 透過它們呼叫函式。

OO和FP是相互排斥的?
這兩者排斥嗎?你能有一種語言既能約束變數再分配和函式指標嗎?當然,這兩者並不是互相排斥的,你可以編寫OO-functional程式。

那是否意味著所有OO程式設計師的設計原則和設計模式都可以被函式程式設計師使用呢?如果他們確實接受物件導向在函式指標上的約束他們就會。

但是函式程式設計者為什麼要這樣做?有什麼好處?他們會得到類似OO程式設計師約束分配的好處嗎?

多型好處
多型只有一個好處,而且很大,能夠將原始碼和執行的依賴進行反轉。

大多數系統一個函式呼叫另外一個函式,執行和原始碼都會發生相同方向的依賴,呼叫模組依賴於被呼叫模組,而多型被注射入於兩者,那麼就存在一個原始碼依賴的反轉,當然執行時刻呼叫模組還是依賴被呼叫模組(原始碼階段不是,是透過反轉或DI依賴注入將依賴的被呼叫模組注入到呼叫模組中),原始碼階段的呼叫模組就再也不依賴被呼叫的原始碼了,而兩者只依賴一個多型介面。

這種反轉允許被呼叫模組扮演一種類似外掛作用,確實,這是也是外掛工作原理。

外掛架構是健壯的,因為穩定的高價值業務規則能夠不再依賴於低價值易變化的模組,比如使用者介面和資料庫(使用者介面是高價值,資料庫易於變化)

最終的結果是,為了是健壯的系統在重大架構內必須使用多型性。

不變性的好處
不再重新分配變數值的好處是:如果你從來不更新就不會有併發更新會發生的問題。

因為函式程式設計不再做變數重新分配,可變性被系統特殊儀式照顧,只是預留給非常需要的時候使用。從多個執行緒和多核角度看這樣做本質上是安全的。

函式程式設計的底線是多處理和多核環境中更加安全。

深層哲學
當然,物件導向和函數語言程式設計信徒們都將抗議我這種簡化分析。 他們會認為,有深厚的哲學區別,以及包括心理和數學原因是他們最喜歡的理由。

我的反應是: 呸!

每個人都認為他們是最好的方式。 每個人都是錯誤的。

設計原則和設計模式?
前面談到了有人認為幾十年以來設計原則和設計模式僅僅適用OO,而函式程式設計將它們減少到:函式。

這個想法是極端的瘋狂。 不管你的程式設計風格軟體設計的原則仍然適用,。 你已經決定使用一種沒有一個賦值運算子的語言並不意味著可以忽略單一責任原則;或自動開閉原則。 策略模式對多型性的利用並不意味著該模式不能用於函式式語言。

底線就在這裡。 物件導向程式設計是好的,只有當你知道它是什麼。 函數語言程式設計是好的,也只有當你知道它是什麼。 函式風格的OO程式設計也是很好的,一旦你知道它是什麼。


[該貼被banq於2014-11-26 09:02修改過]

相關文章