Crystal 的模組有兩個用途:
第一個用途是建立命名空間,避免名稱衝突。 不過,它同時也會將程式碼分組,讓人更容易理解程式碼的用途。
第二個用途是定義混入,把程式碼分享給型別。
模組和類別很相似,但最主要的差別在於模組無法被實體化,因此沒有實體變數。
要宣告一個模組,使用 module 關鍵字,後面接模組名稱。
module Foo
end
命名空間是一種將程式碼分組的方式。
這樣可以避免名稱衝突,也讓人更容易理解程式碼的用途。
當你想存取放在命名空間裡的常數或類別時,可以使用 :: 運算子。
module Foo
class Bar
end
end
Foo::Bar.new
這在許多情況下都很有用,例如多個類別需要相同的「基底」功能,或是程式碼需要在互不相關的類別之間共用。 又或者,你想在彼此沒有關聯的類別之間共用程式碼。
把模組當作混入使用有兩種方式:第一種是使用 include 關鍵字,第二種是使用 extend 關鍵字。
這兩種方法都會讓常數提供給引入或擴充該模組的型別使用。
Include 會讓模組中的所有方法,在引入該模組的型別上以實體方法的形式使用。
include 關鍵字應放在型別的最上方,後面接模組名稱。
module Foo
def foo
"foo"
end
end
class Bar
include Foo
end
Bar.new.foo # => "foo"
Extend 的運作方式和 Include 類似,但它不是讓方法以實體方法的形式使用,而是讓它們以類別方法的形式使用。
extend 關鍵字應寫在型別的最上方,後面接模組名稱。
module Foo
def foo
"foo"
end
end
class Bar
extend Foo
end
Bar.foo # => "foo"
Crystal 中一個常見的模式,是在模組裡使用 extend self 模式。
這會讓模組中的所有方法,在模組本身以類別方法的形式使用。
也就是說,你不需要用 def self.method_name 語法把每個方法都指定給模組。
module Foo
extend self
def foo
"foo"
end
end
Foo.foo # => "foo"
Bellebrook Basketball League 是一個由多支球隊組成的聯盟,每支球隊都有一份球員名單。 新賽季即將開始,他們需要建立一套新的售票系統來販售比賽門票。 上一賽季,他們在體育館入口販售門票,但隨著人氣暴漲,他們決定這一季改在線上售票,以應付增加的需求。
聯盟聯絡了你,請你建立一套系統來處理售票事宜。
首先,你需要建立一套售票系統來處理售票事宜。 這套售票系統需要能顯示一場比賽有多少張門票可供販售。
每場比賽都要建立一個名為 TicketSystem 的類別實例。
初始化的狀態應該包含以下資訊:
從引數建構初始化的狀態,引數分別表示可販售的門票數量,以及比賽舉行的體育館。
初始化的狀態應該由實例變數 @tickets_available 和 @stadium 組成。
這兩個變數應分別存放傳入的第一個和第二個引數。
TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">
首先,你需要建立一個方法,回傳指定比賽可販售的門票數量。
在已定義的類別上方定義一個名為 TicketingReservation 的模組。
這個模組應該被包含進 TicketSystem 類別中。
在模組內定義一個名為 tickets_available 的方法。
這個方法應該回傳可販售的門票數量。
ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100
你必須建立一個方法,檢查指定比賽是否還有門票。 比賽必須保留 100 張門票。 這是為了確保在體育館入口購票的人永遠都能買到票。
在 TicketingReservation 模組內定義一個名為 order_ticket? 的方法。
如果至少還有 100 張門票可供販售,這個方法應該回傳 true,否則回傳 false。
如果至少還有 100 張門票可供販售,這個方法還應該把可販售的門票數量減少 1。
ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true
售票系統的訊息必須讓使用者容易理解。 而且這些訊息應該讓人感到貼心,所以要包含使用者的名字。
如果購票成功,使用者應該會收到一則訊息,告訴他們購票成功、他們的票號,以及比賽在哪座體育館舉行。 票號應該是下單前可販售的門票數量。
如果購票成功,訊息應該長這樣:{name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium.。
如果購票失敗,訊息應該長這樣:{name}, your purchase was unsuccessful, there are not enough tickets available.。
在 TicketingReservation, 模組內定義一個名為 order_message 的方法,它接受一個引數 name,內含購買者的名字。
這個方法應該回傳包含該訊息的字串。
ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."