public, private 和 protected

在某些情况下,你可能希望限制方法的“可见性”(visibility),以确保定义方法的类之外的代码不能调用它们。

当你的类定义了它所需的各种“实用的”(utility)工具方法以执行它不打算公开使用的某些功能时,这将是很有用的。通过对这些方法施加访问限制,你可以阻止程序员将它们用于自己的恶意目的。这也意味着你将能够在以后阶段中更改这些方法的实现,而不必担心你将破坏其他人的代码。

Ruby 提供了三个级别的方法可访问性:

  1. public
  2. protected
  3. private

顾名思义,public 方法是最容易访问的,private 方法是最不易访问的。除非另有说明,否则你编写的所有方法都是公开(public)的。当一个方法是公共(public)的时,它可以被定义该对象的整个类之外的环境使用。

当方法是私有private)的时,它只能由定义该对象的类内的其它方法使用。

一个受保护protected)的方法通常以与私有方法相同的方式工作,但具有一个微小但重要的区别:除了对当前对象的方法可见之外,受保护的方法对于具有相同类型并且处于第一个对象作用域内的第二个对象也是可见的。

当你看一个可运行的示例时,私有和受保护方法之间的区别可能更容易理解。思考这个类:

pub_prot_priv.rb
  1. class MyClass
  2. private
  3. def priv
  4. puts( "private" )
  5. end
  6. protected
  7. def prot
  8. puts( "protected" )
  9. end
  10. public
  11. def pub
  12. puts( "public" )
  13. end
  14. def useOb( anOb )
  15. anOb.pub
  16. anOb.prot
  17. anOb.priv
  18. end
  19. end

我已经声明了三个方法,每个方法都有一个级别的可访问性。这些级别是通过在一个或多个方法之前放置 privateprotectedpublic 来设置的。在指定其它某些访问级别之前,指定的可访问性级别对所有后续方法保持有效。

注意publicprivateprotected 可能看起来像关键字。但事实上,它们是 Module 类的方法。

最后,我的类有一个公共方法 useOb,它将 MyOb 对象作为一个参数并调用该对象的三个方法 pubprotpriv。现在让我们看看如何使用 MyClass 对象。首先,我将创建该类的两个实例:

  1. myob = MyClass.new
  2. myob2 = MyClass.new

现在,我尝试依次调用这三个方法…

  1. myob.pub # This works! Prints out "public"
  2. myob.prot # This doesn't work! I get a 'NoMethodError'
  3. myob.priv # This doesn't work either - another 'NoMethodError'

从上面可以看出,公共(public)方法在调用的对象之外的环境中(正如预期的那样)是可见的。但私有(private)和受保护(protected)的方法都是不可见的。所以,受保护的方法的用途是什么?另一个示例应该有助于理解这一点:

  1. myob.useOb( myob2 )

这一次,我调用了 myob 对象的公共方法 useOb,并且我将第二个对象 myob2 作为参数传递给它。需要注意的重要一点是 myobmyob2 是同一个类的实例。现在,回想一下我之前说过的话:

除了对当前对象的方法可见之外,受保护的方法对于具有相同类型并且处于第一个对象作用域内的第二个对象也是可见的。

这可能听起来像官方话(gobbledygook)。让我们看看是否可以分析一下来理解它。

在程序中,第一个 MyClass 对象(此处为 myob)在当 myob2 作为参数传递给它的方法时,在它的作用域内就有了第二个 MyClass 对象。当发生这种情况时,你可以认为 myob2 存在于 myob 内部。现在 myob2 共享了容器(containing)对象 myob 的作用域。在这种特殊情况下 - 当同一个类的两个对象在该类定义的作用域内时 - 该类的任何对象的受保护(protected)方法将变得可见。

在本例中,myob2(这里名为 anob 的参数 - ‘接收’了 myob2)的受保护方法 prot 变得可见并且可以被执行。然而,它的私有方法仍然是不可见的:

  1. def useOb( anOb )
  2. anOb.pub
  3. anOb.prot # protected method can be called
  4. anOb.priv # but calling a private method results in an error
  5. end