上一篇解釋了 Ruby 如何用全物件來實現物件導向後,在繼承鏈中找尋方法時還有一個很重要的東西 — Module。
本篇將延續上一篇的內容,討論如何透過 include
prepend
和 extend
來引入 Module。
include
加入模組最常用到的是 include
。
當一個 class 使用 include
引入 Module 的時候,會將 Module 內的 method 增加為自己的 instance method:
module Skill
def sit
puts "sit down please"
end
end
class Dog
include Skill
# ...
endbingo = Dog.new
bingo.sit # => sit down please
以繼承練的順序來說,是放在 class 的上方:
> Dog.ancestors
=> [Dog, SKill, Object, ...]
prepend
而如果使用 prepend
來引入 Module, 則會放在繼承練的下方
其實很難想像有什麼場景可以使用到 prepend
,有興趣的可以參考這篇文章中用了 debugger 的例子來展示 prepend
的應用場景。
extend
extend
則是會將 Module 引入到 class 的 singleton class 上方。
也就是說 Module 的 method 會變成 class mehtod
module Instinct
def run
puts "Dogs can run"
end
endclass Dog
extend Instinct
# ...
endDog.run # => Dogs can run
Hook methods
在繼承類別或者引入模組的時候,有一些內建的 hook methods 可以使用:
Module#included
Module#extended
Module#prepended
Class#inherited
舉例來說,include module 後會觸發 included
module MyModule
def self.included(base)
puts "MyModule is included to #{base}"
end
endclass MyClass
include MyModule
end# => MyModule is included to MyClass
像是要實現 Rails 的 Concern,可以使用 hook method 來達到同時可以引入 instance method 和 class method 的功能:
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end module ClassMethods
# ...
end
end
當然在實務上來說,在 Rails 中直接使用 Concern 還是看起來簡潔許多的!