轉 方法多態與Duck typing;C#之拙劣與F#之優雅

來源:互聯網
上載者:User

原文在:http://blog.csdn.net/hikaliv/article/details/4559927

很喜歡懂函數式的,也喜歡對物件導向技術有深入思考的。本文,我很欣賞。

 

方法多態與類型多態

       瞭解 OOP 的同學對類型多態都很熟悉了。話說,類型多態之多態便體現在方法上,那方法多態又是嘛玩兒?類型多態之類型指的是對像的類型,其方法是受對像約束的。方法多態便是不受對像類型約束的多態。具體區別在:

  1. 方法多態無需繼承;類型多態必須實現介面或類繼承。
  2. 方法多態不管你是誰,只在乎你能幹嘛;類型多態講究你出自何門何派。
  3. 方法多態的對像相容性只需其實現運行期被實際調用的方法部分;類型多態的對像相容性要求 A is-a B,也即不管用得著用不著,只要你拜了師傅,就得全部實現。

Duck typing 與方法多態

       Duck typing 是種動態語言的程式設計風格,用以實踐方法多態。概念提出者 James Whitcomb Riley 同學如是說:

       當看到一隻鳥走起來像鴨子,遊起泳來像鴨子,叫起來也像鴨子,那這隻鳥就可以被當做鴨子。

       Duck typing 並不關注對像的類型,而是關注其表現。我們讓某個對像去“走兩步兒”,去“遊兩下”,去“叫兩聲”;若對像無法完成指定動作,則拋出運行時異常——它是運行期檢查的。Duck typing 沒有任何靜態檢查,如類型檢查、屬性檢查、方法簽名檢查等。Guido van Rossum 同學認為,Duck typing 的安全性依賴良好的文檔、清晰的代碼和完備的測試。舉一個 Python 語言的例子:

圖一

       代碼言簡意賅。鴨子和人兩種動物都會 Quack,於是均可傳入 CheckAsDuck 方法處理。CheckAsDuck 只管丫會不會鴨叫,才不管丫是什麼東西。而這種做法在 OOP 思想裡是不可理喻的。

Duck typing 引發的嚴重問題

       Duck typing 表現了動態語言的程式設計思想,其與靜態語言強調的類型檢查不同之處在於:動態語言假設你會做某個動作,運行時可能會發現你其實做不來;靜態語言必須運行前就得確定你能否做得來。Duck typing 更像是種協議,體現著開放與自由——我們歡迎你來參與,希望你能遵守彼此的協約;若你違背或沒能完成指定安排,代價就是運行時異常。而靜態類型檢查更像是種約束,架了道門檻兒——想進來?先看自己夠不夠格兒!

       開放與自由的代價便是運行期風險,一隻殘廢的鴨子和一隻被誤當成鴨子的恐龍都會造成程式崩潰,見如下 Python 樣本:

圖二

       小鴨子是只沒長成的鴨子,還未實現 Sb 方法,因此被 try-except 塊趕出了鴨群;與此同時,恐龍成功模仿鴨子的全部行為被誤當成鴨子允許存取,造成程式崩潰。Python 的異常處理機制簡直就是一條“馬其諾防線”,損己不利人。你也不能怪恐龍故意搗亂,人家的 Sb 方法定義是用在別處的,只不過其 Fck 方法定義給你用的,是你誤把丫當成鴨子強拽過來的,恐龍很冤枉。這個陷阱只能人為規避,動態語言自身無力預防。

C# 的輕薄、無能、無賴和變態

       像 Python 等動態語言那樣“撒鴨子”不管的放縱並不理想;靜態語言中說起強型別約束 C# 典型。一樣本,要是用 C# 怎麼寫 CheckAsDuck 方法?從 OOP 視角需要 Person 類與 Duck 類“發生關係”……二者可均派生自會 Quack 的 QuackAnimal 類,或可均實現有 Quack 方法的 IQuack 介面。選擇派生自基類的設計基本不容考慮,光單繼承這點就受不了;選擇實現介面的設計看似輕便實則臃腫,見如下樣本:

       人就是比鴨和貓能耐大,要求既可被 CallFck 又可被 CallSck,於是,介面汙染。

       為何用 C# 舉例呢?因為 OOP 家族中 C# 太典型了。C# 是 OOP 語言中的春哥純爺們兒!C# 說,咱就是拿純正 OOP 體質和你丫動態語言剛正面,就是不信邪。Rush 失敗,咱有反射(Reflection)技術做後招兒,五;到了 C# 4.0,咱也會玩兒動態(dynamic),六:

       C# 看似豐滿,實則虛胖。C# 背後,對像林立,壁壘森嚴。C# 內個體間互動通訊的成本高。反射最貴。而 C# 4.0 裡的 Dynamic 本質上不過是給反射包了層糖衣而已。動態語義與 OOP 哲學本身就不相容。看著好就不顧自身體質硬上,C# 未免輕薄。《函數式編程之 CPS》文末也提到 C# 3.0 引入 Lambda 是只得其表,不得其裡。如今又強姦動態語義壯陽,有點粉飾其 OOP 體質之無能的味道。

       按說,C++ 不需要反射嗎?C++ 人家有指標呐!俗話說:“指標可以紮透一切!”C++ 的矛利過 C# 的盾。故而 C# 與指標不共戴天。那 unsafe 塊兒呢?尷尬啊!C# 啊,春哥哪是這麼好當的……

       我們能規避反射實現方法多態嗎?做不到。OOP 體質的癥結在哪兒?癥結在 OOP 語言中,函數根本就沒地位。C# 裡唯一有地位的就是對像。沒有游離於對像之外的方法,獨立的方法也需要委託對像去封裝。一方面,C# 的強型別約束被高架在對像層面,不可能透過對像直接操作其內部的方法;另一方面,C# 使用反射如動態語言一般將方法檢查扔給了運行時,這叫玩兒無賴。其作派總結一句話便是:乖乖讓我折磨你,想擺脫淩辱就流放你。本質上,這是在強型別與無類型之間兩極變臉,或者變性。C# 不愧是 OOP 家族的春哥純爺們兒,已是男女不分。

F# 優雅實現方法多態

       動態語言放縱,OOP 語言無能,其中還有 C# 語言玩變態。我們不過是想找一門語言,其方法多態的實現既不受折磨,又確保安全。函數也是具類型的,其類型由參數表與傳回型別決定。故而我們希望可以直接針對函數執行靜態類型檢查。函數式語言中,函數地位顯赫。此刻 F# 挺身而出,替我們實現:

圖七

       F# 中 18 行 inline 和 19 行 ^ 聯袂,直接對參數 duck 對像的成員函數進行靜態類型檢查。23 行貓不能通過檢查,因為其 Fck 成員函數類型不合格。24 行狗不能通過檢查,因為其沒有 Fck 成員函數。

       至於 F# 中 inline 與 ^ 算符如何聯袂完成操作,不在本文的討論範圍,想對 F# 瞭解更多,請查閱《F# 手冊》和《F# 靜態解析變數類型》。 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.