Ruby的中介編程與反射能力示範
在系列文章的前幾篇,我已經說明了 JavaScript 與 PHP 中介編程與反射能力的方式。 本文則就同樣的需求功能,示範 Ruby 的實作方式。
本文所示範的輸出結果,與 JavaScript的中介編程與反射能力示範 、 PHP的中介編程與反射能力示範 相同。 該做什麼,前文都提過了,此處不再重談。
我把 Ruby 的範例程式拆成兩段列出。一方面是為了方便說明。另一方面是為了突顯 Ruby 的 open class 能力。
程式第一段,先定義 MyData
的基本需求: 儲存資料欄位與內容。
請看第21行的動作。 Ruby 的所有實例變數都是 private 的,基本上,在我們定義存取運算子之前應該是不能得知其值的。實際上,我們仍然可以透過反射函數去取得它的值。 PHP 則不允許這麼做。
任何具有強式反射能力的語言中, private 關鍵字和說明文件相差不遠:有需要時,我總是使用反射機制去取得。
《程式設計師提升生產力秘笈》(The Productive Programmer), Neal Ford, O'Reilly出版
接下來的第二段程式,則要擴充 MyData
的定義內容,補上資料欄位的 setter 與 getter 。同時我還要實作 each
方法,讓使用者(外部)不必透過反射函數就能完成走訪動作。
如果我們想為類別增加更多的行為能力,我們既不需要用到繼承,也不需要回到原始定義處修改。Ruby 允許再度添加定義內容到已存在類別。我們需要做的就只是打開它,直接加上我們想要的行為。Ruby 稱之為 open class 。 JavaScript 可以透過 prototype chains 隱蔽地實現 open class 的目的。 在 C++, Java, PHP 中,這種動作會擲出類別已定義的錯誤,它們不允許這麼做。
實作過程中,我在 class_eval
的部份碰到了些麻煩。我原本是想用 define_method
來實現,但是不知為何,它似乎不能在 args.each_pair
區塊內調用。Ruby 會抱怨 define_method
未定義。但若不寫在區塊中則可用。試了幾種不同的手段後,class_eval
似乎是在這種情形下唯一可用的方式。
事實上,在本系列文章中, Ruby 的程式是我第一個寫好的。我寫好後,才回頭去完成 JavaScript 與 PHP 的部份。 就我的範例需求功能來看, Ruby 的實作方式最順暢,效果也最好。例如資訊隱藏的部份, JavaScript 基於本身的特性,無法作到資料保護。程序員仍然可以跳過 setter ,直接改變 props 中的資料欄位內容。JavaScript 的 Prototype 特性略嫌晦澀,就算是老手也偶爾會碰觸到 prototype chains 陷阱。
PHP 則不支援 open class 能力,因此我們要擴充功能時(例如增加 Iterator
的功能),便不能在外面實作,而要進入類別的原始定義處重構。說白話些,就是我們不能分成好幾段源碼文件來寫,而要打開類別第一次定義的源碼檔,修改即有的類別定義源碼。
而且在實作迭代功能時的限制也比較多。
Ruby 提供豐富而一致的表達能力,易於閱讀與理解。它總是能支持我的想法,而不是限制我的想法;Java 常用詭異的方式扭曲我們的思想。同時程式結構還能保有高度的抽象性,讓我不必花太多的功夫在細枝末節上;C/C++ 要花不少精力關注資源釋放的情形。不論是程序式編程、class-based編程還是函數式編程風格, Ruby 幾乎都能滿足。Ruby 確實是很優秀的程式語言
樂多舊回應