再見物件導向程式設計?

banq發表於2016-08-05
一位有著10年物件導向語言的程式設計師對物件導向兩大支柱繼承和封裝提出了自己的疑問,並由此認為可以向物件導向說再見了。

原文:

Goodbye, Object Oriented Programming — Medium

該文從繼承 封裝和多型幾個方面進行了論證。

(1)首先,該文認為繼承是為了重用,所以會導致一個繼承一個,最後很多類會繼承一個大類,本來使用繼承是為了重用這個目地,卻得到複雜的大類,這是香蕉猴子叢林問題(Banana Monkey Jungle)。

其實,透過繼承實現重用只是達到重用的一個很小方面,這種為重用而使用的繼承只有少數幾個場合才可以使用,非常類似於介面和實現,子物件繼承父物件,實際執行是依靠子物件,而在設計時使用父物件,這樣,如果父物件可能有多個子物件,也不會對依賴父物件的各種依賴設計造成衝擊,同時又對變化保持開放,因為子物件數量是開放的,沒有限制的,只要有變化,再做一個子物件即可,這種方式在策略模式中得到很好體現。

所以,透過繼承實現重用不是漫無目的濫用,而是遵循一定業務場景和模式的,如果不遵循設計模式使用物件導向程式語言,必然會造成誤用。

該文提出繼承造成的鑽石問題,其實也是上述錯誤思路的一個結果,總是希望有一個跨領域邊界的絕對正確高高在上的基礎物件,這個基礎物件是為了重用而總結出來的,比如PoweredDevice裝置這個類,如果沒有任何上下文,裝置這個類基本沒有任何含義,該文假設出兩個子類掃描器和印表機繼承這個裝置,然後影印機又要繼承掃描器和印表機,這種兩層繼承關係造成好像鑽石形狀的繼承關係。

說不好聽,這是“作”出來的結果,萬事萬物皆有界,如果忽視客觀世界,紙上玩弄語言當然是自討苦吃,物件的英文是Object,又意味是客體的意思,客觀世界的物件,物件導向主要含義是面向客觀世界的用語言表達出來,不能切分語言的“能指”和“所指”。

按照這種“作”思維拱出來的基類當然脆弱了,可以說是人為製造的全域性真理模型,不符合自然法則。當然脆弱。

從另外一個方面說,繼承使用是有限制的,應用於業務模型是適當的,但是如果應用在沒有客觀世界反映的非業務模型場合,無疑屬於誤用,因為在這些非業務模型場合,無疑是函式模型的天下,是數學模型的天下。

該文認為繼承會帶來層次不清問題,因為父子物件可以互換,實際上混淆設計和執行兩個階段,重用層次都是設計層面的,如果重用與層次使用得到,抽象出框架庫包,這些框架庫包也需要在執行時和子類一起執行。另外,現實世界是多維的,如果將這些多維壓縮到單繼承,實際是降維了,這也會導致層次不夠清楚問題。

讓我們回到原始問題,為什麼要使用繼承? 因為父物件代表忽略細節的抽象,而子物件代表充分細節的實際物件,如果我們這個忽略細節的抽象維度選擇正確了,找到事物不變性規律關係,將很少變化的關係進行抽象,無疑這種不變和可變分離本身已經形成了良好的層次。

(2)該文對OOP的第二個問題封裝也提出了質疑,物件封裝了狀態,防止外界不經過一定業務行為擅自修改。該文認為如果物件被多個物件引用,就導致多個物件會修改該物件內的狀態。

比如A是一個代表狀態物件,傳遞給B,B保護其它作為私有欄位:

Class B{
   private A a;

   public B(A a){
      this.a = a;
    }


}
<p class="indent">


上述狀態A傳遞入B被保護起來,但是透過B構造器傳入,而呼叫B的其他類在構造B時同時也要構造A,所以,在這個環節A是不安全的。

這個問題單獨看好像確實是一個問題,但是實際專案中依賴注射首先能解決這個問題,其次,狀態是經常變化的,狀態總是有一個初始狀態,這個初始狀態是透過配置等方式設定的,不是由程式設定的。必要時,狀態的克隆也不是非常耗費效能。在DDD中,將狀態封裝為值物件進行復制或共享是常用的事。

如果瞭解DDD,DDD透過聚合根這種設計將狀態保護得更加完備,保證了聚合內部狀態變化的一致性,如同資料庫多個關聯表之間同時改變一樣。

(3)該文最後對多型性提出了異議,認為介面實現才是真正多型實現,其實物件導向程式語言不只是支援介面,還支援多種多型實現,比如透過AOP或Mixin等方式實現,多型性體現了對變化開放的一種方式。

總之,面嚮物件語言用於結合物件導向的分析設計方法,作為對客觀世界的業務跟蹤和記錄無疑是非常適合的,如果脫離業務分析,那麼函式式語言是非常合適的,沒有副作用,沒有可變狀態,進入了純粹邏輯世界。

物件導向世界除了繼承和介面以外,還有關聯和聚合等組合方式,後兩者才是物件導向世界的重要核心,也是經常使用的兩種方式,繼承是初學者容易誤用的方式,將繼承看成是物件導向程式設計的首要特點本身也是有誤導的。

以上是本人的反駁一面之詞,也可見另外一篇反駁的英文文章:

Lamenting the Death of Object-Oriented Programming. (Sigh) Again?

[該貼被banq於2016-08-05 19:57修改過]

相關文章