module
一個最簡單的module
include
在class使用include, 可以讓module內的方法為class的物件方法,在ruby稱為mixin
include可用在模擬多重繼承,因Ruby不像C++可以直接多重繼承,所以宣告為module,在mixin到class裡面
extend
在class使用extend,可以讓module內的方法為class的類別方法
與include的不同點在於
- include: module內的方法為class的物件方法
- extend: module內的方法為class的類別方法
module Foo
def foo
puts 'foo'
end
end
class Bar
extend Foo
end
Bar.foo # 印出hello foo (foo已成為Bar的類別法)
self in module
self是什麼?就是呼叫Ruby當前物件本身指標所指的,在主程序直接呼叫self返回main。
先看最簡單的module
module Foo
end
直接呼叫self會出現什麼呢?
module Foo
p self #印出 Foo
end
別忘了ruby式腳本式的語言,這個程式沒寫錯,單純只是宣告module,他裡頭的命令句還是被執行,所以印出Foo
那麼這個Foo物件是什麼?簡單,印出來看看
module Foo
p self.class #印出Module
end
非常清楚,Ruby號稱所有東西都是物件,所以module也是物件,所以self的使用很清楚了,直接動態的在Foo物件上面加上方法
module Foo
def self.foo
puts 'hello foo'
end
end
Foo.foo # 印出hello foo, 直接呼叫Foo這個Module形態的物件,裡頭的foo方法
所以同理,class裡面的self也是一樣的應用,class也是可以實體化為物件,並動態的加上方法,通常稱為類別方法,這種類別方法,在其他程式語言裡面也很常用,只是實作方式不同,Ruby是把class也當作物件處理
extend self
綜合上面所說的,如果module裡面 extend self會發生什麼事呢?
module Foo
extend self
def foo
puts 'hello foo'
end
end
Foo.foo # 印出hello foo
如果在class內使用extend會使module內的方法,成為類別方法,那如果在module使用,同樣會成為module方法,這個講法並不好,因為在Ruby裡面都是物件,只是在其他語言稱為類別方法,所以我照著命名
extend self如果有點難懂,先看extend 別的模組
module Foo
def foo
puts 'hello foo'
end
end
module Bar
extend Foo
end
Bar.foo # 印出hello foo (foo成為bar的類別方法)
就在跟class裡面extend一樣。同理extend self,就可以讓自己本身的方法,可以用module方法的方式呼叫,也可以被class include時,被當成物件方法呼叫
module_function
從名稱得知,使用module_function,則只能當成module function來使用
將要變成module function的方法名稱,使用symbol的方式傳入
module Foo
def foo
puts 'hello foo'
end
module_function :foo
end
Foo.foo 印出hello foo(變成module方法)
跟上面extend self不同的是,它就只能當module方法,如果在class內include,也不會變成物件方法
module Foo
def foo
puts 'hello foo'
end
module_function :foo
end
class Brb
include Foo
end
Foo.foo # 印出hello foo
brb = Brb.new
brb.foo # 跳出NoMethodError錯誤,因為foo只能當module方法,不是當物件方法來呼叫
included
還有一個動態的方法,讓class include時,再決定哪些是類別方法,哪些是物件方法
module內建一個方法叫做include,可以在該module被include時被呼叫,舉個例子
module Foo
def self.included(receiver)
puts "#{self}被#{receiver} include進去了"
end
end
class Brb
include Foo #印出Foo被Brb include進去了
end
所以我們可以在module內決定include它的class要哪些類別方法,幫它(class)呼叫extend就行了,例如
module Bar
def bar
puts 'hello bar'
end
end
module Foo
def self.included(receiver)
receiver.extend Bar # 幫它(class)呼叫extend 並extend Bar進去
end
end
class Brb
include Foo
end
Brb.bar # 印出hello bar
同理,也可以幫它呼叫include
module Bar
def bar
puts 'hello bar'
end
end
module Foo
def self.included(receiver)
receiver.send :include, Bar # 幫它(class)呼叫include 並include Bar進去
end
end
class Brb
include Foo
end
brb = Brb.new
brb.bar # 印出hello bar
也可以在module直接嵌套在module裡面 讓程式馬更簡潔,下面示範嵌套完,並直接呼叫extend與include
module Foo
module Bar # 將用來當類別方法
def bar
puts 'hello bar'
end
end
module Bla # 將用來當物件方法
def bla
puts 'hello bla'
end
end
def self.included(receiver)
receiver.extend Bar # 將Bar設定為類別方法
receiver.send :include, Bla # 將bla設定為物件方法
end
end
class Brb
include Foo
end
Brb.bar
brb = Brb.new
brb.bla
沒有留言:
張貼留言