1. 程式人生 > Ruby 程式語言入門 >15 Ruby 的模組

15 Ruby 的模組

我們在之前的章節中介紹了類,在本章節中,我會來介紹一下 Ruby 模組的概念以及如何去使用一個模組。

1. 什麼是模組?

在 Ruby 中,模組在某種程度上類似於類:它們可以持有方法,就像類一樣。但是,和類不同的是無法例項化模組,即模組不可以建立物件。因此,與類不同,模組沒有new方法。

那麼哪裡需要使用模組呢?

使用模組,您可以在類之間共享方法:模組可以包含在類中,這使得它們的方法可以在多個類中使用,就像我們將這些方法複製並貼上到類定義上一樣。這種使用方式我們也稱為Mixin

2. 模組的使用

2.1 建立模組

建立模組的時候我們會用到關鍵字module

例項:

module Encryption
end

現在我們就建立了一個什麼方法都沒有的Encryption模組。

2.2 新增方法

與類中定義例項方法一樣,在模組中建立方法只需在模組中定義一個方法即可:

require 'digest'

module Encryption
  def encrypt(string)
    Digest::SHA2.hexdigest(string)
  end
end

現在模組擁有了一個名為encrypt的方法。這個方法是用於將傳入字串進行 SHA256 加密。

注意事項:因為和類不同,模組沒有new方法,不能例項化成為一個物件,所以不能模組一般通過被類進行引用來執行相應的方法。

Encryption
.new # ---- 輸出結果 ---- undefined method `new' for Encryption:Module (NoMethodError)

不過,模組可以通過模組名.方法名()的形式呼叫模組方法

例項:

require 'digest'

module Encryption
  def self.encrypt(string) # 注意這裡多了一個self
    Digest::SHA2.hexdigest(string)
  end
end

puts Encryption.encrypt('super password')

# ---- 輸出結果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'

模組方法的定義形式和類完全一樣,因為模組就是類(Class)的父類(Superclass)(在 類的實質 章節中會詳細講解)。

class Person
end

p Person.class.superclass

# ---- 輸出結果 ----
Module

2.3 通過引用模組重構程式碼

讓我們用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


# ---- 輸出結果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'

Person類擁有一個對密碼加密的方法,讓我們對這個方法進行重構。

我們要重構這個獲取對密碼進行加密之後的結果的方法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


# ---- 輸出結果 ----
'02f10a4b97a846ae06d64073bb56469d8516bbe19bd1487e9d80ae7e9ec0ac1b'

解釋: 在這裡我們使用了include關鍵字來引用模組(引入模組一共有三種方式:includeextendprepend,在之後的章節中我們會對這三種情況逐個分析),引用的方法都會變成Person類的例項方法。重構後,我們呼叫encrypted_password時加密時使用的encrypt方法來自Encryption模組內,這樣避免了在很多類中做同一種加密,每修改一次加密形式就要修改每一個類程式碼的問題。

上述這種情況假設我們還有其它需要加密內容的類,我們還希望將加密的方法保留在一個地方,這麼做有 4 個好處:

  • 當我們想切換到另一種加密方式的時候,只需要更改這個模組的加密程式碼即可;

  • 我們不希望相同的加密邏輯程式碼在某些需要的位置重複被使用;

  • 可以把這種程式碼視為一個雜物,隱藏在另一個檔案中,我們只需要關心類的工作,不需要關心加密事務的具體邏輯;

  • 使用模組來封裝程式碼也會使可讀性更高。

3. 小結

本章節中我們學習了模組的概念,區分了類與模組,模組不能建立例項,沒有new方法,以及如何建立一個模組,向模組中新增方法、建立類似類方法的模組方法、引用模組,引用模組封裝程式碼的好處。