Ruby 的模塊
我們在之前的章節(jié)中介紹了類,在本章節(jié)中,我會來介紹一下 Ruby 模塊的概念以及如何去使用一個模塊。
1. 什么是模塊?
在 Ruby 中,模塊在某種程度上類似于類:它們可以持有方法,就像類一樣。但是,和類不同的是無法實例化模塊,即模塊不可以創(chuàng)建對象。因此,與類不同,模塊沒有new
方法。
那么哪里需要使用模塊呢?
使用模塊,您可以在類之間共享方法:模塊可以包含在類中,這使得它們的方法可以在多個類中使用,就像我們將這些方法復(fù)制并粘貼到類定義上一樣。這種使用方式我們也稱為Mixin
。
2. 模塊的使用
2.1 創(chuàng)建模塊
創(chuàng)建模塊的時候我們會用到關(guān)鍵字module
:
實例:
module Encryption
end
現(xiàn)在我們就創(chuàng)建了一個什么方法都沒有的Encryption
模塊。
2.2 添加方法
與類中定義實例方法一樣,在模塊中創(chuàng)建方法只需在模塊中定義一個方法即可:
require 'digest'
module Encryption
def encrypt(string)
Digest::SHA2.hexdigest(string)
end
end
現(xiàn)在模塊擁有了一個名為encrypt
的方法。這個方法是用于將傳入字符串進行 SHA256 加密。
注意事項:因為和類不同,模塊沒有new
方法,不能實例化成為一個對象,所以不能模塊一般通過被類進行引用來執(zhí)行相應(yīng)的方法。
Encryption.new
# ---- 輸出結(jié)果 ----
undefined method `new' for Encryption:Module (NoMethodError)
不過,模塊可以通過模塊名.方法名()
的形式調(diào)用模塊方法。
實例:
require 'digest'
module Encryption
def self.encrypt(string) # 注意這里多了一個self
Digest::SHA2.hexdigest(string)
end
end
puts Encryption.encrypt('super password')
# ---- 輸出結(jié)果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'
模塊方法的定義形式和類完全一樣,因為模塊就是類(Class)的父類(Superclass)(在 類的實質(zhì) 章節(jié)中會詳細講解)。
class Person
end
p Person.class.superclass
# ---- 輸出結(jié)果 ----
Module
2.3 通過引用模塊重構(gòu)代碼
讓我們用Person
類舉例:
require 'digest'
class Person
def initialize(name)
@name = name
end
def name
@name
end
def password=password
@password = password
end
def encrypted_password
Digest::SHA2.hexdigest(@password)
end
end
person = Person.new("Andrew")
person.password = "super password"
p person.encrypted_password
# ---- 輸出結(jié)果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'
Person
類擁有一個對密碼加密的方法,讓我們對這個方法進行重構(gòu)。
我們要重構(gòu)這個獲取對密碼進行加密之后的結(jié)果的方法encrypted_password
。在這時我們選擇引用Encryption
模塊來添加對字符串加密的encrypt
方法。
實例:
require 'digest'
module Encryption
def encrypt(string)
Digest::SHA2.hexdigest(string)
end
end
class Person
include Encryption
def initialize(name)
@name = name
end
def name
@name
end
def password=password
@password = password
end
def encrypted_password
encrypt(@password)
end
end
person = Person.new("Andrew")
person.password = "super password"
p person.encrypted_password
# ---- 輸出結(jié)果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'
解釋: 在這里我們使用了include
關(guān)鍵字來引用模塊(引入模塊一共有三種方式:include、extend、prepend,在之后的章節(jié)中我們會對這三種情況逐個分析),引用的方法都會變成Person
類的實例方法。重構(gòu)后,我們調(diào)用encrypted_password
時加密時使用的encrypt
方法來自Encryption
模塊內(nèi),這樣避免了在很多類中做同一種加密,每修改一次加密形式就要修改每一個類代碼的問題。
上述這種情況假設(shè)我們還有其它需要加密內(nèi)容的類,我們還希望將加密的方法保留在一個地方,這么做有 4 個好處:
-
當(dāng)我們想切換到另一種加密方式的時候,只需要更改這個模塊的加密代碼即可;
-
我們不希望相同的加密邏輯代碼在某些需要的位置重復(fù)被使用;
-
可以把這種代碼視為一個雜物,隱藏在另一個文件中,我們只需要關(guān)心類的工作,不需要關(guān)心加密事務(wù)的具體邏輯;
-
使用模塊來封裝代碼也會使可讀性更高。
3. 小結(jié)
本章節(jié)中我們學(xué)習(xí)了模塊的概念,區(qū)分了類與模塊,模塊不能創(chuàng)建實例,沒有new
方法,以及如何創(chuàng)建一個模塊,向模塊中添加方法、創(chuàng)建類似類方法的模塊方法、引用模塊,引用模塊封裝代碼的好處。