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。
相關文章
- Logstash中的ruby
- JavaScript 中的模組化JavaScript
- Python中的abc模組Python
- python中的chardet模組Python
- Python中模組的使用Python
- Nodejs中的stream模組NodeJS
- Ruby中的陣列陣列
- rust模組管理示例1Rust
- Python中operator 模組的用法Python
- Python中pathlib 模組的用法Python
- Python中itertools 模組的用法Python
- Python中paramiko 模組的用法Python
- python中重要的模組--asyncioPython
- javascript中的模組系統JavaScript
- 探索 JS 中的模組化JS
- Python 中argparse模組的使用Python
- Magix中的快取模組快取
- SpringBoot多模組專案中無法注入其他模組中的spring beanSpring BootBean
- pickle模組 collections模組在物件導向中的應用物件
- Ruby中的true和falseFalse
- Ruby中 ?與!的慣例
- Ruby中的設計模式設計模式
- [Ruby Summit 2018 話題分享] 模組化的 Rails,微服務以外的另一種選擇MITAI微服務
- Python中os模組Python
- Python中yaml模組的使用教程PythonYAML
- [譯] Swift 模組中的 API 汙染SwiftAPI
- Python中的collections.Counter模組Python
- Python中模組是什麼?Python有哪些模組?Python
- 【比賽】CSP提高組模擬1
- nodejs模組載入分析(1).mdNodeJS
- 螞蟻SOFA系列(1) - 聊聊SOFA的模組化
- java中呼叫npm模組JavaNPM
- django中admin模組中修改密碼的formDjango密碼ORM
- Dill模組中的引用、父母和孩子
- Python中的mechanize模組是什麼?Python
- python中的itertools模組簡單使用Python
- [譯] 瀏覽器中的 ECMAScript 模組瀏覽器
- 序列化模組,隨機數模組,os模組,sys模組,hashlib模組隨機