[转]Method visibility in Ruby

From: http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby
A common point of confusion to even experienced Ruby programmers is the visibility of public, protected, and private methods in Ruby classes. This largely stems from the fact that the behavior of those keywords in Ruby is different from what you might have learned from Java and C.

To demonstrate these differences, let’s set up a little script:


class Foo
  def a; end

  # call 'a' with explicit 'self' as receiver
  def b; self.a; end

  # call 'a' with implicit 'self' as receiver
  def c; a; end
end

def safe_send(receiver, method, message)
  # can't use 'send' because it bypasses visibility rules
  eval "receiver.#{method}"
rescue => e
  puts "#{message}: #{e}"
else
  puts "#{message}: succeeded"
end

visibility = ARGV.shift || "public"
Foo.send(visibility, :a)

foo = Foo.new
safe_send(foo, :a, "explicit receiver       ")
safe_send(foo, :b, "explicit 'self' receiver")
safe_send(foo, :c, "implicit 'self' receiver")

Basically, the script just creates a class “Foo” with three methods: a, which we’ll invoke directly with an explicit, non-self receiver; b, which invokes a with self as receiver, and c, which invokes a with an implicit receiver of self. We’ll use the safe_send method to call each of those methods and log the result.

So, first: the public keyword. In Ruby, public means that the method may be invoked just about any way you please; in technical terms, the receiver of the message may be either explicit (“foo.bar”), self (“self.bar”) or implicit (“bar”).

引用
$ ruby demo.rb public
explicit receiver       : succeeded
explicit 'self' receiver: succeeded
implicit 'self' receiver: succeeded

The protected keyword puts a straitjacket around the method. Any method declared protected may only be called if the receiver is self, explicitly or implicitly. (Update: protected methods may actually be called any time the receiver is of the same class as ‘self’...and an explicit self as receiver is just a specific case of that. Modifying the script to demonstrate this condition is left as an exercise for the reader.)

引用
$ ruby demo.rb protected
explicit receiver       : protected method `a' called for #<Foo:0x3fc18>
explicit 'self' receiver: succeeded
implicit 'self' receiver: succeeded

Lastly, the private keyword is the tightest setting of all. A private method cannot be called with an explicit receiver at all, even if that receiver is “self”.

引用
$ ruby demo.rb private
explicit receiver       : private method `a' called for #<Foo:0x3fc18>
explicit 'self' receiver: private method `a' called for #<Foo:0x3fc18>
implicit 'self' receiver: succeeded

Note that, unlike languages such as Java, inheritance plays absolutely no part in determining method visibility in Ruby. Subclasses can access both protected and private methods of the superclass without trouble, so long as they abide by the rules laid out above.

The difference between protected and private is very subtle, as you can see, which explains why protected is rarely used by most Rubyists. If it is used at all, it is generally as a convention, to document methods that are internal to the class, but which lie closer to the public interface than others. In Rails, for instance, you might declare your controller filter methods and model validation methods as “protected” (because the framework will call those methods) and reserve the “private” designation for those methods that are only ever called from within your own model or controller code.

你可能感兴趣的:(visibility)