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/
發佈留言