因為 Class method 是 global method 所以可以到處被使用
就像 User.all
這樣的方法可以在 model, controller, view 都被使用
Class method 有什麼問題?
代表你可以隨處使用而不必在乎前後因果
class User
def self.email_to(id, email)
user = User.find(id)
Emailer.send(email, "Hello, #{user.name}")
end
下面這是更好一點的版本,因為寄信這件事情應該可以直接針對該 user,也就不用在去 find 了
class User
def email_to(email)
Emailer.send(email, "Hello, #{name}")
end
這樣一來你在別處執行的 code 可能就會變成
user = User.find(params[:id])
user.email_to(email)
而不是 class method
User.email_to(params[:id], email)
因為 class method 不是在一個 object instance 上面操作,是 global 都能使用,這其實不太符合 OOP 精神,尤其 ruby 又是這麼 OOP 的一個語言(萬物皆為 object)。
Class method 的寫法比較像是程序式程式語言(Procedural programming) 然而 instance method 在 object 創建本身就需要帶完整和正確的參數,在 debug 上有一定的優勢。
我個人比較偏好寫 instance method,因為 object instance 再做完他的工作就死了,不會有污染的問題…
所謂污染就是把 object 能做的事情丟給 global 做就會變成這樣
# 應該要用 class 的 new 去做,但自己寫了 initialize?
module Hello
def self.initialize(first_name, last_name)
@@first_name = first_name
@@last_name = last_name
end
def self.fullname
"#{@@first_name} #{@@last_name}"
end
end
# 假設有一個 class 要使用 Hello module
class Cool
def boy
# 這時候強制設定了 class 層級的 local variable
Hello.initialize("Nic", "Lin")
puts Hello.fullname
end
def girl
# 然後又把 local variable 覆蓋了...
Hello.initialize("Doris", "Lin")
puts Hello.fullname
end
end
# 執行
example_1 = Cool.new
example_1.boy
# Nic Lin
example_1.girl
# Doris Lin
執行起來沒問題,但是在這個層級裡面,你的 Hello module 其實偷偷覆寫了 local variable,這是一個非常危險的事情。
我知道這 example 看起來很蠢,但確實存在。
小結
如果不是可以全域使用的方法,我認為還是用 instance method 好一些,尤其很多 service 的邏輯封裝,更不適合這樣污染。
並不是說 class method 不好,只是覺得如果要運用不該是到處氾濫,畢竟我們很常用一些好用的 class method 例如 User.find
, User.all