inherited、included、extended 方法


如果類別定義有inherited類別方法,被子類別繼承時,inherited會被呼叫,並傳入子類別作為引數。例如:
>> class Some
>>     def self.inherited(clz)
>>         puts "#{self} is inherited by #{clz}"
>>     end
>> end
=> nil
>> class Other < Some
>>     puts self
>> end
Some is inherited by Other
Other
=> nil
>>


注意inherited被執行的時機,是在子類別本體執行之前。一個應用的例子,在 抽象類別與介面 中談過,模擬了Java中抽象類別的概念。

如果模組中定義有included模組方法,在被其它類別含括時,included方法會被呼叫,並傳入含括類別的模組作為引數。例如:
>> module M1
>>     def self.included(clz)
>>         puts "#{self} is included by #{clz}"
>>     end
>> end
=> nil
>> class Some
>>     include M1
>> end
M1 is included by Some
=> Some
>>


一個應用的例子,在 抽象類別與介面 中談過,用模組來模擬Java中interface的概念。另一個常見應用,是讓模組可以定義各類別共用的類別方法。例如:
# encoding: Big5
module M1
def self.included(clz)
def clz.execute
puts "共用的 execute 類別方法"
end
end
end

class Some
include M1
end

class Other
include M1
end

Some.execute # 顯示 "共用的 execute 類別方法"
Other.execute # 顯示 "共用的 execute 類別方法"

如果模組定義有extended方法,其它實例使用extend方法擴充模組時,extended方法會被呼叫,並傳入實例作為引數。例如:
>> module M1
>>     def self.extended(o)
>>         puts o
>>     end
>> end
=> nil
>> o = Object.new
=> #<Object:0x27dfa28>
>> o.extend(M1)
#<Object:0x27dfa28>
=> #<Object:0x27dfa28>
>>


就類別而言,開啟類別使用include來含括模組,與使用類別的extend來擴充模組,雖然作用是相同的,但會觸發的方法並不同,分別是included與extended,你也可以同時定義兩個方法,讓include與extend時,都呼叫同一個方法:
# encoding: Big5
module M1
def self.included(clz)
self.set_execute_class_method(clz)
end

def self.extended(obj)
self.set_execute_class_method(obj)
end

def self.set_execute_class_method(clz)
def clz.execute
puts "共用的 execute 類別方法"
end
end
end

class Some; end
class Other; end

Some.extend(M1)
Other.extend(M1)

Some.execute # 顯示 "共用的 execute 類別方法"
Other.execute # 顯示 "共用的 execute 類別方法"