Ruby 使用手冊

存取控制 Access control

之前我們說過,Ruby 沒有函數,只有方法。但 Ruby 有不只一種的方法, 本節將介紹存取控制 (access controls)

如果我們在「最高層級」(top level) 定義方法,而不是在類別中定義,那會怎樣呢?我們會發現這個方法與 C 這種傳統語言中的函數 (function) 相似。

ruby> def square(n)
    |   n * n
    | end
   nil
ruby> square(5)
   25

我們的新方法不屬於任何類別,但其實 Ruby 將它指定為 Object 類別,即所有類別的父類別。因此,任何物件現在都能使用這個方法。但有個小問題:這是所有類別的私有 (private) 方法。我們之後會解釋這是甚麼意思,但其中一個影響就是它只能以函數的方式呼叫出來,如下所示:

ruby> class Foo
    |   def fourth_power_of(x)
    |     square(x) * square(x)
    |   end
    | end
  nil
ruby> Foo.new.fourth_power_of 10
  10000

我們不能明確地將該方法應用於物件:

ruby> "fish".square(5)
ERR: (eval):1: private method `square' called for "fish":String

這樣就能聰明的保留 Ruby 的純物件導向特質(函數仍為物件方法,只是接收器 (receiver) 是隱含的 self 而已)。

物件導向程式設計的常見心智訓練 (mental discipline)(曾在之前章節透露過),在於辨別規格 (specification)實作 (implementation),或是物件應該要完成甚麼 (what) 工作,以及如何 (how) 完成。使用者一般不知道物件的內部運作方式,只需要了解輸入輸出的是甚麼,並相信物件的內部運作即可。因此,不同類別擁有外界不知道的方法,有時也是有用的,但這些方法只用於內部(有需要的話,程式員可予以改進,而不改變使用者對於物件類別的看法)。以下範例中,請想像 engine 是該類別的隱形內部運作方式。

ruby> class Test
    |   def times_two(a)
    |     puts "#{a} times two is #{engine(a)}"
    |   end
    |   def engine(b)
    |     b*2
    |   end
    |   private:engine  # 讓使用者看不到 engine
    | end
   Test
ruby> test = Test.new
   #<Test:0x4017181c>
ruby> test.engine(6)
ERR: (eval):1: private method `engine' called for #<Test:0x4017181c>
ruby> test.times_two(6)
6 times two is 12.
   nil

我們會預期 test.engine(6) 傳回 12,但我們在外使用 Test 物件時,engine 方法是不能呼叫的。只有其他 Test 的方法(如 times_two)才能使用 engine。我們需要使用公開介面 (public interface) 的 times_two 方法。負責該類別的程式員能夠隨意變更 engine(可能把 b*2 改為 b+b,假設引數提高了效率),而不會影響使用者與 Test 物件的互動。這個例子確實比較簡單,但我們創造更複雜有趣的類別時,存取控制的優點就會更明顯。 (編註:這就叫做物件導向的封裝概念)

Copyright (c) 2005-2008 Mark Slagell,中文翻譯 Ruby Taiwan 社群

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is included in the section entitled "GNU Free Documentation License."