php mix-in delegate ruby
第一部份《PHP 實踐 mix-in 概念之可行性》一文中解釋了 PHP 的個體如何加入新的方法。但那僅針對個體而非類別,那些混成內容無法繼承再用。而 Ruby 的混成(mix-in)概念是針對類別,其混成結果是一個類別,這些混成內容可經繼承機制再用。所以我接下來就要為 PHP 實踐一個可以混成的類別 - MixableClass
。
我的設計目標有二。第一、個體可以動態增刪方法,且不影嚮其他個體。第二、以抽象化方法混成新的類別。
個體可以動態增刪方法
我可以將某類別的實例視為獨立個體,僅為此個體增添方法,而不經類別關係影嚮其他同類或衍生類別之個體。舉例而言,當我配置了個體 $x 之後,我可以只為 $x 增加 foo 方法。而其他個體不論是否與 $x 同類,皆不會自動具有 foo 方法。這一點在第一部份《PHP 實踐 mix-in 概念之可行性》已經實現了。
以抽象化方法混成新的類別
可用「與特定類別無關的抽象化方法」混成新的類別,且混成類別的特徵仍然要與一般類別相同。
- 混成基礎類別的方法可為衍生類別所繼承。
若我以 foo 方法混成了 MyClass 類,則繼承 MyClass 類之 MyClass2 類也會具有 foo 方法。
- 這些混成類別可以隨時增刪方法,且動態增刪之方法亦須依繼承原則運作。
若我將 foobar 方法動態加入 MyClass2 類,不僅所有已配置之 MyClass2 實例將立即具有 foobar 方法,連其衍生類別 MyClass3 之實例也將依繼承原則而具有 foobar 方法。
- 遵循子承父、父不承子之繼承原則。
當我動態加入 foobar 方法至 MyClass2 類後,衍生類別 MyClass3 將繼承 foobar 方法,但基礎類別 MyClass 不會繼承 foobar 。
在此有必要說明我所稱之「抽象化方法」為何?抽象化方法之意義與抽象類別 (abstract class) 或抽象方法 (abstract function) 不同。抽象方法與特定類別封裝在一起,且僅具函數簽名而不具有任何定義內容(沒有程式碼)。而我說的「抽象化方法」與特定類別無關但具有定義內容(有程式碼),可以將其視為純粹的演算法,是 Metaprogramming 中的一種概念。
混成類別: MixableClass.php
我設計了 MixableClass
實踐上述目標。在實作過程中,碰到了 PHP 動態能力不足之處,導致我必須多方嘗試並連帶影嚮實作結果的使用效能。這些狀況容我日後再提。
PHP 將方法混入個體或類別的方式,接近 C# 的委派方式,如同《Delegate in C# and Module in Ruby》所示。所以我以 delegate 表示混入方法。
MyClass_test.php
執行結果:
invoke $x->foo()
FOO Xman
invoke $y->foo()
FOO Yman
invoke $z->foo(), $z->bar()
FOO Zman
BAR
========== 動態混入/委派 =============
invoke $z->foobar("z")
ERR: fobar 尚未混入 MyClass3 ; MyClass3 尚未委派 foobar 行為.
foobar 混入 MyClass2 ; MyClass2 委派 foobar 行為.
invoke $z->foobar()
FOOBAR (z) Zman
子承父。MyClass2 的衍生類別 (MyClass3) 承繼其委派之 foobar.
invoke $y2->foobar()
FOOBAR (y2) Y2man
invoke $x->foobar()
ERR: 父不承子。MyClass2 的基礎類別 (MyClass) 仍無 foobar 行為.
========== 實例行為委派,不混入類別中 =============
invoke $x->myBar()
BAR
invoke $x2->myBar()
ERR: myBar 並未混入類別
invoke $y->myBar()
ERR: myBar 並未混入類別
上例之類別繼承關係如下圖所示。
各位不妨再看看「Prototype-based programming in PHP」以及「我也來實作 PHP mix-in 的概念」。他們的設計目標與我略有不同,可兩邊比較設計內容。
相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/2884871.html
樂多舊回應