天天看點

Ruby元程式設計(讀書筆記)-第1章

第1章 元這個字眼

元程式設計是編寫能寫代碼的代碼

1.1 鬼城與自由市場

語言構件(language construct)包含各種成員(變量、類、方法等)。

以C++為例,一旦編譯器完成了工作,變量和函數這樣的東西就變得看不見摸不着了,它們隻存在于記憶體中。你沒有辦法向一個類詢問它的執行個體方法,因為當你問出這個問題時,它可能已經消失了。對于C++這樣的語言來說,運作時(runtime)是一個可怕的寂靜之地----鬼城。

而在另外一些語言(如Ruby)中,運作時更像是一個繁忙的自由市場。大多數語言構件依然存在,而且正四處忙碌着。你甚至可以抓住一個構件,詢問它關于它自身的問題。這種方式稱作内省(introspection)

讓我們通過一個執行個體來看看内省究竟是什麼。

class Greeting
    def initialize(text)
        @text = text
    end
    
    def welcome
        @text
    end
end           

複制

my_object = Greeting.new("Hello")

這裡定義了一個Greeting類,并建立了一個Greeting對象。現在我們可以抓住這個對象,并像它提問:

my_object.class #=> Greeting

我問它所屬的類,它十分肯定的回答我:“我是一個Greeting”,現在我要問它有哪些執行個體方法:

my_object.class.instance_methods(false) #=> [:welcome]

我得到的回答是一個數組,其中隻有一個方法welcome。參數false代表我是問它自己的方法,不要它繼承來的方法。接着,我問它有哪些執行個體變量:

my_object.instance_variables #=> [:@text]

它如實回答了我的問題。類和對象都是Ruby世界的一等公民,你可以問出很多資訊來。

Ruby元程式設計(讀書筆記)-第1章

ruby

Ruby除了可以在運作時詢問語言構件,還能在運作時建立它們。在程式運作時,能否在welcome方法之外再添加一個執行個體方法?你可能不太了解,究竟什麼情況下會有這樣的需求呢?請看下面的故事。

1.2 程式員Bob的故事

Bob有一個計劃:為電影迷建造一個世界最大的網際網路社交系統。為了實作這個目标,他先要建立一個存放電影名和影評的資料庫。Bob希望借此機會練習編寫可重用的代碼,是以他決定建立一個簡單的代碼庫,用于在資料庫中實作對象的持久化。

1.2.1 Bob的第一次嘗試

Bob編寫了一個代碼庫,把資料庫中的每個表映射到一個類中,同時把每條記錄映射到一個對象中。每當創一個對象或通路它的屬性時,這個對象會産生一條SQL語句并發送給資料庫。所有這些功能都封裝在一個類中。

class Entity
    attr_reader :table, :ident
    def initialize(table, ident)
        @table = table
        @ident = ident
        Database.sql "INSERT INTO #{@table} (id) VALUES (#{@ident})"
    end
    
    def set(col, val)
        Database.sql "UPDATE #{@table} SET #{col}='#{val}' WHERE id=#{@ident}"
    end
    
    def get(col)
        Database.sql ("SELECT #{col} FROM #{@table} WHERE id=#{@ident}")[0][0]
    end
end           

複制

在Bob的資料庫中,每個表都有一個id字段。每個Entity會儲存這個字段的内容以及它引用的表名。每建立一個Entity對象後,該對象會把自己儲存在資料庫裡。Entity#set方法建立SQL語句更新字段值,而Entity#get方法建立SQL語句讀取字段值。(Bob的Database類用二維數組作為傳回的資料集)

Bob可以繼承Entity類來映射一個指定的表。例如,用Movie類映射一個名為movies的表:

class Movie < Entity
    def initialize(ident)
        super "movies", ident
    end
    
    def title
        get "title"
    end
    
    def title=(value)
        set "title", value
    end
    
    def director
        get "director"
    end
    
    def director=(value)
        set "director", value
    end
end           

複制

Movie類的每個屬性有兩個方法:一個讀方法和一個寫方法。Bob隻要在Ruby指令行解釋器中輸入如下指令,就能把一部電影加載到資料庫裡:

movie = Movie.new(1)
movie.title = "Doctor Strangelove"
movie.director = "Stanley Kubrick"           

複制

Bill看了Bob的代碼後說:“重複的代碼太多了。資料庫裡有title字段,代碼裡有@title成員,還有title方法、title=方法、title字元串常量。如果你會元程式設計,用很少的代碼就可以解決這個問題。”

1.2.2 進入元程式設計的世界

==未完待續==