ruby 中的 forwardable 模組(1)
forwardable模組
最近在看rack-attack原始碼的過程中,看到了這個模組。ruby的語法糖實在是太豐富了,各種特性看得人一臉懵逼。幸好各位前輩留下了許多文章去給我們指點迷津,這篇文章對forwardable的描述我覺得很通俗異動,很適合我們對這個模組有一個比較淺顯的理解。
Forwardable 是一個模組,中文名翻譯為委託,包含了一些方法可用於向給定類的所有例項新增行為 ( behavior )。
在 Ruby 內部實現時,使用了 extend 關鍵字將此模組包含進 singleton 類,為此可以在類級別向類新增方法 ( 保持簡單 )。簡單來說,就是利用Ruby 提供的訊息轉發系統避免了建立一個 getter 方法來訪問我們所需要的元素。
def_delegator 方法
在介紹forwardable的這些API方法之前,我們先舉一些簡單的例子來給看看我們為什要使用這些方法,觀察一下這些方法給我帶來了什麼便利。
class Hero
attr :skills
def initialize
@skills = [:strong, :keen, :brave]
end
end
jack = Hero.new
puts "Jack's main skill: #{jack.skills.first}"
執行結果如下:
Jack's main skill: strong
這能正常工作,但, 在 Hero 類定義之外呼叫 jack.skills.first 稍微有點冗餘,我們可以first方法進行一次封裝。因此,讓我們將此程式碼封裝到 Hero 類定義中:
class Hero
attr :skills
def initialize
@skills = [:strong, :keen, :brave]
end
def main_skill
@skills.first
end
end
jack = Hero.new
puts "Jack's main skill: #{jack.main_skill}"
在這裡,我們會得到和不封裝前一樣的輸出。但是ruby提供了一種更優雅的機制,Forwardable#def_delegator 方法允許物件將訊息轉發到定義的接收器,我們現在先按照這種機制修改一下程式碼:
require 'forwardable'
class Hero
attr :skills
extend Forwardable
def_delegator :@skills, :first, :main_skill
def initialize
@skills = [:strong, :keen, :brave]
end
end
jack = Hero.new
puts "Jack's main skill: #{jack.main_skill}"
上面的程式碼中
- 首先,我們載入了 forwardable 模組
- 其次,我們使用 extend Forwardable 關鍵字將該模組的方法新增到 Hero 類級別中
- 最後,我們使用新新增的類級方法 def_delegator,我們的例項子jack是我們的物件,是我們的轉發者。第一個引數 :@skills 對應於訊息轉發的接收者,第二個引數 :first 是要轉發的訊息,最後是第三個引數 :main_skill 是 :first 訊息的別名。當我們呼叫 jack.main_skill 時, 它比 jack.first 更可讀,然後在內部自動呼叫 skills.first。
def_delegators 方法
def_delegators 方法與 def_delegator 方法類似,兩個方法的主要區別是,def_delegators 方法需要一組方法來轉發,並且方法不能別名。
require 'forwardable'
class Todolist
attr :tasks
extend Forwardable
def_delegators :@tasks, :first, :last
def initialize
@tasks = %w[conception implementation refactoring]
end
end
todolist = Todolist.new
puts "first tasks: #{todolist.first}"
puts "last tasks: #{todolist.last}"
輸出結果為:
first tasks: conception
last tasks: refactoring
在這個示例中,tasks 陣列的 firt 和 last 方法可用於任何 Todolis 例項, 當呼叫這兩個方法其中之一時,訊息將被轉發到 tasks 陣列。
delegate 方法
delegate 方法接受一個雜湊 ( hash ) 作為引數,其中鍵 ( key ) 是一條或多條訊息,
值 ( value ) 是 鍵對應的訊息的接收器。
require 'forwardable'
class Computer
attr :cores, :screens
extend Forwardable
delegate %I[size] => :@cores,
%I[length] => :@screens
def initialize
@cores = (1..8).to_a
@screens = [1, 2]
end
end
macrosoft = Computer.new
puts "Cores: #{macrosoft.size}"
puts "Screens: #{macrosoft.length}"
輸出結果為:
Cores: 8
Screens: 2
上面的示例中,macrosoft.size 訊息對應於 macrosoft.cores.size,macrosoft.length 訊息對應於 macrosoft.screens.length。
相關文章
- ruby_expect模組的使用..薦
- Ruby中的陣列陣列
- Logstash中的ruby
- Ruby中的設計模式設計模式
- Ruby中的true和falseFalse
- Ruby 2.0 Preview 1釋出View
- Ruby 中陣列的常用操作陣列
- ruby 字串學習筆記1字串筆記
- Ruby 中的閉包-程式碼塊
- ruby中的== eql?和equal?區別
- ruby中的\z與\Z區別
- Ruby中的Profiling工具
- Ruby中的TypeError異常處理Error
- 對比Ruby和Python的垃圾回收(1)Python
- ruby中proc和lambda的return區別
- ruby中迭代器列舉器的理解
- RUBY-FLEX實踐—利用swfobject在RUBY工程中載入SWFFlexObject
- Ruby on Rails中的MVC架構是如何工作的AIMVC架構
- [讀書筆記] Ruby 中的 Block 和 Iterator筆記BloC
- Ruby on rails專案中 引入BootstrapAIboot
- [Ruby]format xml with RubyORMXML
- Python中的模組--SSH相關模組Python
- Ruby中的設計模式——《松本行弘的程式世界》設計模式
- JavaScript 中的模組化JavaScript
- 在 Ruby 中執行 Shell 命令的 6 種方法
- Ruby動態刪除方法中的列印語句
- 如何在 Ruby 2.6 中開啟 JIT?
- 那是我午後陽光下的奔跑 -- Ruby中Symbol的想法Symbol
- 解剖Nginx·模組開發篇(1)跑起你的 Hello World 模組!Nginx
- 開發新手最容易犯的50個 Ruby on Rails 錯誤(1)AI
- Ruby程式語言與Ruby之間的比較
- 開發者最討厭的程式語言:PHP、Ruby 中槍PHP
- 探索 JS 中的模組化JS
- javascript中的模組系統JavaScript
- Python中的abc模組Python
- python中的chardet模組Python
- Python中模組的使用Python
- Nodejs中的stream模組NodeJS