在面試 RoR 時,Instance(實例) 和 Class(類別) variable 的差異算是蠻常見的問題,但一陣子沒寫 Ruby 一時又忘記了…因此記錄一下讓自己之後可以回來複習 🥲
Class(類別) Variable
語法表示為 @@var,代表這個變數是屬於類別本身及其子類別所共用的變數,可以想像為 singleton(單例) 模式,不管你從哪個子類別去存取這個變數,都會是同一個值。
直接來看個範例(類別變數會在繼承中共享):
# 假設你有不同類別代表不同種類的訂單,但需要一個統整的總訂單數
class Order
@@total_orders = 0
def initialize
@@total_orders += 1
end
def self.total_orders
@@total_orders
end
end
class OnlineOrder < Order; end
class StoreOrder < Order; end
10.times { OnlineOrder.new }
5.times { StoreOrder.new }
puts Order.total_orders # => 15 (類別變數 @@total_orders,在繼承樹中共享)
puts OnlineOrder.total_orders # => 15 (類別變數 @@total_orders,在繼承樹中共享)
puts StoreOrder.total_orders # => 15 (類別變數 @@total_orders,在繼承樹中共享)
Instance(實例) Variable
語法表示為 @var,代表這個變數是屬於類別物件本身的,每個物件都有一個自己的變數,因此你可以在此維護每個物件的狀態,不會被其他物件影響。
一樣來看個範例(實例變數屬於個別物件):
class Order
@@total_orders = 0
attr_reader :item_count
def initialize(item_count = 0)
@item_count = item_count
@@total_orders += 1
end
def self.total_orders
@@total_orders
end
end
class OnlineOrder < Order; end
class StoreOrder < Order; end
online_order = OnlineOrder.new(10)
store_order = StoreOrder.new(5)
puts online_order.item_count # => 10 (實例變數 @item_count 在每個物件中獨立)
puts store_order.item_count # => 5 (實例變數 @item_count 在每個物件中獨立)
puts Order.total_orders # => 2 (類別變數 @@total_orders,在繼承樹中共享)
puts OnlineOrder.total_orders # => 2 (類別變數 @@total_orders,在繼承樹中共享))
puts StoreOrder.total_orders # => 2 (類別變數 @@total_orders,在繼承樹中共享)
總結
- Class(類別) Variable:
其實不太常用,因為這種變數在繼承樹和類別物件中是共享的,會比較容易導致意外的副作用。 - Instance(實例) Variable:
經常用來維護類別物件中的狀態,每個物件都有自己的變數,不會被繼承且不會互相影響。