在 Ruby 中,除了前幾章提到的 "Block" 不是物件以外,其他的東西都是物件。
但那物件又是什麼東西呢?
物件(Object) = 狀態(State) + 行為(Behavior)
在生活中,交通工具、動植物、你跟我,只要是看得到、摸得到都可以稱為物件(Object)。
而這些物件都會有狀態跟行為,像是貓有「橘色的毛」、「胖的」、「6歲」等狀態,當然也會有「吃飯」、「走路」、「睡覺」等行為。
不曉得大家有沒有吃過雞蛋糕,而雞蛋糕的模具就是個類別 (Class) 的概念,而做出來的雞蛋糕的概念可以叫做實體(Instance)。
所以按照上面的例子,我們可以透過類別(class)組織和產生許多具有相似屬性(attributes)和方法(methods)的物件。
在 Ruby 要定義一個累別,使用 class
:
class MethodName
# ...
end
在 Ruby 中,慣例來說 Class 會以大駝峰 (CamelCase) 來命名,像是:User、BlogsController ...等。
我們也可以透過 Class.new('argument')
來建立物件。
class Dog
def eat(food)
puts "#{food} 好吃!"
end
end
yui = Dog.new
yui.eat("西莎") # 印出 西莎 好吃!
lucky = Dog.new
lucky.eat "牛肉" # 印出 牛肉 好吃!
這邊我用 Dog 類別做了兩個不同的實體,也就是 yui
、 lucky
,這兩個物件因為都是用 Dog
類別做出來的實體,所以都會有 eat
方法。
現在的雞蛋糕有各式各樣的口味,如果在一開始加入巧克力就可以做出巧克力口味的雞蛋糕。
以上面的例子來看,當使用 new
方法作實體的時候,也可以順便傳參數進去,如下:
class Dog
def initialize(name, gender)
@name = name
@gender = gender
end
def say_hi
puts "hi, my name is #{@name}, I'm #{@gender}."
end
end
yui = Dog.new("Yui", "female")
yui.say_hi # 印出 hi, my name is Yui, I'm female.
若要用 new
方法傳參數進來,在類別裡面必須有個名為 initialize
的方法來接收傳進來的參數。在 initialize
方法裡,常見的手法是會把參數傳進來給內部的實體變數(instance variable)。
Day03 的有提到實體變數,那實體變數是什麼呢?
在 Ruby 裡的實體變數是 @
開頭的變數,活在每個實體裡的變數,而且每個實體之間互不相影響。
以上面的例子來看, @name
跟 @gender
就是實體變數。
在 Rails 專案中,實體變數使用的頻率很高,最常用的地方是 Controller 與 View 之間的溝通,舉例來說:
class BlogsController < ApplicationController
def index
@articles = Article.all # 取得所有的 Article 資料
end
end
實體方法就是作用在實體上的方法。
這句話有點像是廢話,舉例來說:
class Dog
def say_hi(name)
puts "hello, #{name}"
end
end
yui = Dog.new
yui.say_hi("Yui") # 印出 hello, Yui
這邊的 say_hi
是作用在 yui
的實體,這稱 say_hi
為實體方法。
類別方法指的是可以作用在類別上的方法。
class BlogsController < ApplicationController
def index
@articles = Article.all # 取得所有的 Article 資料
end
end
這邊 all
方法是直接作用在 Article
這個類別上,所以稱為類別方法。
self
建立類別方法如果不想這麼麻煩,我也可以用 self
,如下:
class Dog
def self.all
# ...
end
end
這時我就可以用 Dog.all
來呼叫方法。
如果你也不喜歡這樣的寫法也可以這樣寫:
class Dog
class << self
def all
# ...
end
end
end
我用下面的例子來總結一下實體方法與類別方法:
class Hello
def say_instance(name)
puts "Hi! 我是實體 (#{name}) 方法"
end
def self.say_class(name)
puts "Hello! 我是類別 (#{name}) 方法"
end
end
greet = Hello.new
greet.say_instance("instance") # Hi! 我是實體 (instance) 方法
Hello.say_class("class") # Hello! 我是類別 (class) 方法
類別的方法存取限制常見的主要有三種: public
、 protected
以及 private
。
參考資料: