本節書摘來自華章出版社《effective ruby:改善ruby程式的48條建議》一書中的第2章,第2.3節,作者 [美]彼得 j.瓊斯(peter j. jones),更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
ruby中,類沒有傳統的oop式的構造方法。如果想要控制對象的初始狀态,我們得寫一個名為initialize的方法并在那裡做必要的工作。在一個新對象被配置設定空間之後,就會在new中調用這個方法。如果你不在自己的類中自定義initialize方法,你的類将從basicobject類中繼承預設實作。不過這并不那麼有效。事實上,那是個空方法,什麼也沒做。它隻是在那裡,使得new方法在你沒有自定義initialize方法時有處可調。還好,很多時候basicobject#initialize就可以滿足你的需要了。不過當你需要自定義initialize方法時是個小例外。
有一點特别容易被忽略,initialize方法其實隻是一個正常的私有執行個體方法,是以它遵循所有正常方法搜尋規則。比如,如果你想,你能定義reset方法來簡單地調用initialize方法把所有執行個體變量重設為其初始值。不過把initialize方法作為正常方法調用會造成令人驚訝的結果。當你定義initialize方法時你也重載了所有在繼承體系中其他更高層的initialize的定義。如果在你曾用過的語言中存在正式的構造方法,你可能希望所有的繼承體系中的方法會鍊在一起而非互相重載。不過在ruby中和你想得不太
一樣:

來看方法parent#initialize,很容易看出,當建立一個新的parent對象時,執行個體變量@name會被初始化為一個預設值。也很容易看出當建立一個child時,方法child#initialize會為執行個體變量@grade指派。可能不清楚的問題就是,建立一個child對象是否也能為@name賦初始值。在irb中運作這些代碼就可以搞清楚這個問
題了:
啊!ruby不能自動調用被重載的方法,即使在initialize方法中也不行。本例中child::new沒有調用parent類裡的initialize方法,因為child類有自己的initialize方法,它重載了父類的這個方法。重寫帶參的initialize方法将使事情更清楚些。
如今你能看到這個窘境了。ruby沒有為我們提供給子類和其超類的initialize方法建立聯系的方式。是以沒辦法知道如何自動調用超類中的initialize方法并傳遞正确的參數。于是這個任務留給了我們。這對新手ruby程式員來說是件令人驚訝的事情,甚至老手也會不一定記得。
既然ruby不會為我們初始化父類,我們該如何完成它呢?為initialize方法準備的解決方案和重載其他方法一樣。也就是說,我們可以使用通用意義上的super關鍵字來調用繼承體系中位于高層的方法。
在放棄了自動構造方法的同時我們獲得了靈活性。使用super調用超類的initialize方法讓我們擁有了如何初始化超類以及在什麼時候初始化超類的控制權。超類應該在子類之前初始化嗎?在初始化超類之前我們需要設定一些環境變量嗎?我們可以自由地按照需要安排這些行為。隻要記住用super就行,花點時間複習一下super的各種用法吧,見第7條。
在總結之前,我得提醒你initialize不是建構新對象的唯一方式。ruby允許我們使用dup和clone方法建立對象的副本。當你使用這些方法中任一個時,可以通過定義initialize_copy方法對新建立的副本對象執行一些特别的邏輯。如果你從超類重載initialize_copy方法,你一定想使用super來正确地建構它。
要點回顧
當建立子類對象時,ruby不會自動調用超類中的initialize方法。作為替代,正常的方法查詢規則也适用于initialize方法,隻有第一個比對的副本會被調用。
當為顯式使用繼承的類定義initialize方法時,使用super來初始化其父類。在定義initialize_copy方法時,應使用相同的規則。