
來源 http://jozefkrajcovic.sk/
Ruby 是一個完全物件導向程式語言,不管是字串、整數等,都是類別的物件。
在物件導向內,類別 (class)主要有方法 (method) 等組成,藉由呼叫方法來改變物件的狀態,Ruby 對方法的存取控制分為三個不同的層級,名稱與其他物件導向程式語言一樣,有 public、protected、private。
Public、Protected、Private 存取控制
在 Ruby 這三個存取控制層級與其他語言有不同之處,從其他語言跳到 Ruby 可能會忽略掉。
- public 可以被任何人直接存取,例如:類別的物件可以呼叫 public 方法,預設所有的方法為 public,除了
#initialize方法為 private - protected 層級比 public 小,只有相同類別或子類別內,才能存取 protected 方法
- private 不能有明確的 receiver 呼叫 private 方法,表示 private 方法只能在物件內被呼叫
還是以下藉由程式來說明會更清楚!
存取控制
接著介紹撰寫方法的存取控制:
第一種寫法:
class Person
def initialize (name, age)
@name = name
@age = age
end
def introduce
talk "Hello! My name is #{@name}"
talk my_age
end
# starting of protected access control level
protected
def my_age
"I'm #{@age} years old."
end
# before private, ending of protected access control level
private
def talk(sentance)
puts sentance
end
end
第一種寫法是將存取控制層級寫在方法前,此種寫法是存取控制層級後面的方法,都是遵照前面所寫的,直到遇到另一個存取控制層級。
如上面的程式碼,寫在 protected 之後的方法都是 protected 的存取層級,直到下一個存取層級,也就是 private,所以,在 protected 與 private 前的方法都是 protected。
Person 類別內所有方法的存取層級分別為:
#initialize– private#introduce– public#my_age– protected#talk– private。
PS. 在前面有提到,#initialize 預設為 private。
第二種寫法:
class Person
def initialize (name, age)
@name = name
@age = age
end
def introduce
talk "Hello! My name is #{@name}"
talk my_age
end
def talk(sentance)
puts sentance
end
def my_age
"I'm #{@age} years old."
end
protected :my_age
private :talk
end
第二個寫法是在方法之後,才定義方法的存取層級,分別在 protected、private 方法後面利用 symbol 來定義每個方法的存取控制層級。
接著我們來操作 Person 類別:
require_relative "person" person = Person.new "AMing", 24 person.introduce # Person#my_age is protected method #person.my_age # Person#talk is private method #person.talk
如果外部程式,要呼叫 Person#my_age、Person#talk 會發生錯誤,因為兩個方法分別為 protected 與 private。
繼承
建立一個 Male 類別,Male 繼承了 Person 類別:
require_relative "person"
class Male < Person
def introduce
super
# In parent class, Person#talk is private method
talk my_sex
end
private
def my_sex
"My sex is male."
end
end
會發現第 7 行程式,在 Male#introduce 內,呼叫了 Person#talk,但是此方法為 private,為什麼 Ruby 可以這樣使用呢?
在一開始介紹 Ruby 的 private 存取控制層級就有提到,private 是不能被明確的 receiver 呼叫。在第 7 行內,#talk 並不沒有 receiver,所以在這裡是合法的,但是如果將第七行改成 self.talk my_sex 就會出現問題,因為 #talk 已經被明確的 receiver 也就是 self 呼叫了!
操作 Male 類別:
require_relative "male" male = Male.new "Johnson", 26 male.introduce
不過,還是有可以在外面程式呼叫 protected 及 private 方法,去參加開開心心學 Ruby 的時候,大大有提到可以利用 Object#send 來呼叫 protected 及 private 方法。
require_relative "male" male = Male.new "Johnson", 26 male.introduce # use Object#send puts male.send :my_age male.send :talk, "private method is called"
不過這樣做,並沒有違反 Ruby 定義的 protected 及 private,以 private 來說,因為並不是由 receiver 去呼叫的,而是透過 #send 方法。
更多詳細的介紹可以參考:http://blog.eddie.com.tw/2011/07/26/public-protected-and-private-method-in-ruby/