Ruby元编程
現在關于Ruby元編程可以說比較熱門,這個隱藏在Ruby背后的特性隨著大家對Ruby的了解逐漸顯現出來啦。這篇文章是自己對Ruby MetPrgamming的理解。
元編程中的元是指元信息(Meta),主要是為其載體提供基本信息,如html頁面中就有meta,如content type說明,SEO等。在C++,Java和Ruby語言中,也有元信息概念,如加載到內存中(運行期)的當個對象模型(Class或者Object),都會包含元信息(藍色)和執行代碼(灰色):
圖中藍色區塊表示元信息,C++最少,在C++編譯的過程中,編譯器僅保留了很少的元信息;Java次之,包含了部分元信息;Ruby在解析過程中保留很多信息,所以元信息最多。當然這里不能說C++設計不合理,C++流行的時候,那個時候內存說不定是640K的,硬盤16M的,如果保留過多的信息,那勢必導致程序無法運行,這些設計都是出于性能的考慮。當然Java在后續的版本(Java 9,Java 10?)中可能會添加更多的元信息,都不確定,畢竟語言在發展。
就一個Class來說,這些元信息是什么,如Java,元信息區塊包括編譯版本號、類名、屬性、函數方法名、返回值、參數類型、annotation等等,這個我們可以通過查看Java Class文件得知。對于Ruby來說,元信息則更豐富,如對函數來說,函數的參數名都會保存下來。接下來還有一個關于元信息的是否可以修改的問題,C++和Java中,這些元信息都是只讀的,你不能更改。一個例子,我們在做Java Debug的時候,如果我們修改函數內部的邏輯,那么hotspot機制可以重新加載該class,但是你給Java Class添加屬性或函數后,hotspot機制會警告你無法進行新的class加載,這個時候我們需要重新啟動應用進行debug。當然也不是絕對的,JavaRebel能夠在修改Java Class結構后,仍能重新加載,其主要是其修改了Java對象模型,不在這里討論。但是Ruby就不一樣拉,元信息不是封閉的,是可以動態修改的,這樣就可以在運行期調整其結構。綜合上述的討論,Ruby的元信息豐富,且可以動態修改,所以我們可以就元信息進行更多的編程,實現某些特殊的功能,而C++和Java在這方面就表現的比較弱一些。
講述了元信息,那么什么是元編程?就是利用元信息進行編碼,也就是你的代碼中包含對元信息的訪問和修改。網上有對元編程的定義為”Write code to write code”(利用代碼去寫代碼),可能不便于理解,如你編寫Maven Plugin或者Velocity模板來生成代碼,這些都不是元編程,因為它們壓根就沒有接觸元信息,就是代碼生成工具而已。在Java中,如果你的代碼訪問了元信息(java.lang.reflect下的類),我們就說你使用了反射機制,反射其實就是Java中的元編程,所以這里將代碼中涉及元信息的操作定義為元編程。在代碼中如何訪問元信息?其實很簡單,有相關的API,如Java中,java.lang.reflect下的類都是圍繞元信息設計的。在Ruby中,和Java一樣,有相關的函數,如instance_methods、class_eval, instance_eval, define_method等等,這些函數主要負責訪問和修改元信息,網上有很多文章介紹這些函數的,不會很難理解。
為何要進行元編程?我們寫代碼主要是為了實現業務邏輯,如數據庫操作,調用搜索引擎等,而元編程只是在操作元信息,好像和業務邏輯無關,其實不然。我們訪問和修改元信息主要目的有兩個:簡化代碼和實現復雜邏輯。簡化代碼雖然不直接為業務邏輯服務,但是會降低維護成本,如動態函數定義等都是這樣的目的;實現復雜邏輯,舉一個例子,如Java中,我們利用反射機制來實現AOP,這樣一些復雜的功能(事務、監控統計、Cache、權限控制等)就非常容易實現。在Ruby中,使用元編程實現的ActiveRecord讓復雜的數據庫操作更加簡單,利用Ruby元編程可以實現各種DSL,如Sinatra就是HTTP的DSL。
我們進行元編程的主要目的是解決業務邏輯實現中的技術問題,所以元編程時有一定的適用場合,不是說利用元編程實現某種奇淫技巧,造成代碼理解困難,增加維護成本,那就不必要啦。元編程也有一些局限性:
1 動態結構更改可能導致某些不可預料的錯誤,如程序A按照既定的邏輯編程,而B程序使用元編程,更改了相關的元信息,導致邏輯不正確,這些都是有的;
2 元編程屬于高級技術,不是一般人能理解,而且不是面向業務的,使用不好反而會增加維護成本;
3 對IDE工具不友好,IDE工具對強類型語言,如Java支持非常好。如果你在Ruby中動態定義一些函數(如使用class_eval),那么IDE將無法完成這些動態定義的函數提示,開發效率也會降低的,不過不少IDE(如RubyMine)已經開始著手解決這些問題。
最后說明一下,元編程并不是某種語言的專利,其實每種語言都包含的這樣的特性,只不過支持的程度不一樣。Ruby設計的對象模型讓元編程更容易實現,而且非常容易實現一些復雜功能,所以這也成了Ruby的特點,這些特點在Rails的代碼中體現的尤為明顯,甚至到了極致的地步,所以也成就了Rails這款非常優秀的框架。
總結
- 上一篇: 几种方法来实现scp拷贝时无需输入密码
- 下一篇: Boost库实现线程池学习及线程实现的异