定義類別之後,可以使用new方法來建構物件,實際上new是類別方法,預設的動作是配置新物件、以傳入的參數呼叫initialize方法進行物件初始化、傳回物件。
既然new是類別方法,你可以重新定義new方法。例如:
>> class Some
>> def self.new(*args)
>> puts "new"
>> o = self.allocate
>> o.send(:initialize, args)
>> o
>> end
>> def initialize(*args)
>> puts args
>> end
>> def x
>> puts "x"
>> end
>> end
=> nil
>> s = Some.new
new
=> #<Some:0x516de0>
>> s.x
x
=> nil
>>
>> def self.new(*args)
>> puts "new"
>> o = self.allocate
>> o.send(:initialize, args)
>> o
>> end
>> def initialize(*args)
>> puts args
>> end
>> def x
>> puts "x"
>> end
>> end
=> nil
>> s = Some.new
new
=> #<Some:0x516de0>
>> s.x
x
=> nil
>>
以上是個new方法的流程示意,allocate方法會配置新物件,但不執行initialize方法,由於initialize方法是private,所以無法透過o.initialize方式呼叫,而使用了 淺談物件、訊息與方法 中談過的send方法呼叫,new方法傳入的引數,會傳給initialize方法。
在介紹 陣列型態、雜湊型態 等物件時,介紹過new方法可以指定程式區塊進行初始化,實際上程式區塊會傳給initialize方法,如果你在initialize方法中使用yield,就可以執行程式區塊。例如:
>> class Orz
>> def initialize(n)
>> n.times do |i|
?> yield(i + 1, "orz")
>> end
>> end
>> end
=> nil
>> Orz.new(5) do |n, msg|
?> puts "#{n} - #{msg}"
>> end
1 - orz
2 - orz
3 - orz
4 - orz
5 - orz
=> #<Orz:0x24e4c60>
>>
>> def initialize(n)
>> n.times do |i|
?> yield(i + 1, "orz")
>> end
>> end
>> end
=> nil
>> Orz.new(5) do |n, msg|
?> puts "#{n} - #{msg}"
>> end
1 - orz
2 - orz
3 - orz
4 - orz
5 - orz
=> #<Orz:0x24e4c60>
>>
如果要模擬以上行為,可以使用以下程式:
>> class Orz
>> def self.new(*args, &block)
>> o = self.allocate
>> o.send(:initialize, *args, &block)
>> o
>> end
>> def initialize(n)
>> n.times do |i|
?> yield(i + 1, "orz")
>> end
>> end
>> end
=> nil
>> Orz.new(5) do |n , msg|
?> puts "#{n} - #{msg}"
>> end
1 - orz
2 - orz
3 - orz
4 - orz
5 - orz
=> #<Orz:0x21e5980>
>>
>> def self.new(*args, &block)
>> o = self.allocate
>> o.send(:initialize, *args, &block)
>> o
>> end
>> def initialize(n)
>> n.times do |i|
?> yield(i + 1, "orz")
>> end
>> end
>> end
=> nil
>> Orz.new(5) do |n , msg|
?> puts "#{n} - #{msg}"
>> end
1 - orz
2 - orz
3 - orz
4 - orz
5 - orz
=> #<Orz:0x21e5980>
>>
Ruby中並不支援其它程式語言中解構方法的定義,不過可以透過ObjectSpace.define_finalizer來達到類似的效果。例如:
class Some
def initialize(value)
@value = value
ObjectSpace.define_finalizer(self,
self.method(:finalize).to_proc)
end
def finalize(object_id)
puts "Destroy #{object_id} Some(#{@value})...."
end
end
Some.new(10)
Some.new(20)
Some.new(30)
ObjectSpace.garbage_collect # 提示 GC
執行結果如下:
Destroy 16096056 Some(30)....
Destroy 16096140 Some(20)....
Destroy 16096224 Some(10)....
Destroy 16096140 Some(20)....
Destroy 16096224 Some(10)....