Delegate in C# and Module in Ruby
我在《類別繼承、介面宣告與模組混成(mix-in)》中提到 Java 的介面(interface) 無助於提高程式碼再用性。而 jaceju 在回應中提醒我還有 delegate 這種方式。
我當年學的是 Java 1.0 ,那時的 Java 還沒有 delegate 這種概念。對我這個在 C/C++ 中用慣函數指標的人而言,沒有函數指標或類似方式是一件非常彆手彆腳的事。後來我在 C# 中碰過 delegate ,直覺反應這是 C# 版的函數指標。而 Java 則以類別型式的 Delegate 實踐此概念。但是 delegate 與 Ruby 的混成(mix-in)概念相比,還是很麻煩... 非常麻煩,不會比 PHP 好到哪去。
Ruby 之模組的作法
首先,我們先看看 Ruby 的混成(mix-in)的作法。我定義了一個模組 MySampleModule
及一個類別 MyClass
。MyClass
類之建構子定義了一個實例變數 @title。 Ruby 的實例變數對應於 C++/C#/Java 中的私有資料成員 (See also: Ruby Reference: Instance Variable)。而在 MySampleModule
模組中定義了一個方法 show
,請注意到它將顯示 @title 的內容,而 @title 在模組中並未出現。Ruby 對此採動態繫結策略:根據實際調用此方法之個體決定 @title 指涉何者。
C# 之 delegate 的作法
接著我們來看看 C# 的 delegate 作法。實際上,它和 PHP 的作法非常相似,參閱《PHP 實踐 mix-in 概念之可行性》。差別僅在於 PHP 以「名」參照,將之稱為 Variable function 。所以 jaceju 說有點 delegate 味道
。
為了方便閱讀, C#的例子中所用名稱和 Ruby的例子中一樣。與 Ruby 的模組語法相比,不難發現 delegate 的語法冗長多了。它必須先宣告 delegate 函數簽名 methodDeleagte
,接著再宣告方法 show
並委派 MySampleModule.show
處理。語法上有兩個缺點。其一、若 MySampleModule
中有多個方法且函數簽名皆不同時,MyClass
就必須宣告多個 delegate 函數簽名。其二、當我們在 MySampleModule
中增加新的方法時,我們也必須在 MyClass
中增添委派的程式碼;Ruby 完全隱藏於 include MySampleModule
之中,我們不須處理。
實際使用時,它所面臨的狀況和 PHP 一樣,不能使用 this 存取活動個體之屬性。MySampleModule
本身是一個類,其中的 this 被認定指涉 MySampleModule
類之實例。即便我們委派 MySampleModule.show
為 MyClass
類之 show
方法,並藉由 MyClass
之實例 x 調用,MySampleModule.show
中之 this 仍不會動態繫結至 x。Ruby 會將實例變數動態繫結至活動個體;JavaScript 也會將 this 動態繫結至活動個體。在 Ruby 與 JavaScript 之方法內出現的屬性存取對象,係依此方法為哪個個體所調用而定 - 若為 x 所調用,則屬性存取對象就是 x 之屬性;若為 y 所調用,則為 y 之屬性。在 C# 中,屬性存取對象則依此方法定義於哪個類別中而定 - 若為 MySampleModule
所定義,則屬性存取對象必須是 MySampleModule
之實例。
C#的解決方式也和 PHP 一樣,屬性必須宣告為 public ,並將 this 作為引數傳遞給委派方法。當限制與解決方式相同時,程式碼的行數就是關鍵。C#所需的行數比 PHP 還多出許多, C# 之 delegate 比 PHP 的作法麻煩。與 Ruby 相比就更不用談了。
樂多舊回應