Ruby 中 private 和 protected 的消息 ( Message ) 机制

yufei       3 月, 2 周 前       77

作为一个 Ruby 方法,与返回对象的指令块相关联 message handler 一般都是在后台运行。所以,privateprotected 策略也就和消息 ( message ) 概念息息相关了。

这么拗口,读到这里,你可能和作者我一个想法:privateprotected 一般不都是用来修饰类成员的吗,什么是 privateprocted 策略呢 ?

哈哈,别着急,为了方便大家理解 private 和 protected 策略,我们先快速回顾一下 Ruby 消息概念

消息 ( Message ) 、接收器 ( Receiver ) 和 消息处理器 ( Message Handler )

消息 由名称 ( 通常是符号 ( symbol ) ) 和可选的有效内容 ( payload ) ( 也就是参数列表 ) 组成

一个消息需要一个接收器 ( receiver ,通常是一个对象 ) 通过 消息处理器 ( 通常是一个方法 ) 来响应和处理

而消息的发送方始终是调用对象上下文。如果从类上下文外部调用消息,那么就是 main 对象

我们可以使用 Kernel#send 方法向接收者明确发送消息

 receiver        name   payload
     |              |       |
 __________      ______  ______
 "a-string".send(:split, '-', 3)

上面的代码中,一个消息由以下几个部分组成

  1. 接收者 "a-string"
  2. 消息名称 :split
  3. 消息内容 ( payload ) : '-',3
  4. 发送者: main 对象

这段代码,我们也可以做如下解释

"a-string" 通过消息处理器 String#split 响应了一个名为 :split 的消息。

拗口的要死,其实你应该更熟悉另一个语法

```ruby receiver name payload | | |


"a-string".split('-', 3) ```

上看这段代码,我们可以这样理解: 一个带有 '-',3 消息内容的名为 split 的消息立即被发送给接收者 a-string

解释来解释去,不知道你是否已经理解了 Ruby 中消息的概念。如果理解了,那么我们就继续讲解 privateprotected 方法的概念

私有 ( private ) 方法

Ruby 中,一个私有的方法或私有的消息处理器只能够响应具有隐式接收器 ( self ) 的消息。它无法响应从私有消息处理程序上下文(对象)外部调用的消息

也就是说,私有消息或私有方法只能处理对象内部的消息,也只能发给对象内部的接收器。

 class Receiver
  def public_message
    private_message
  end
  def self_public_message
    self.private_message
  end
  private
  def private_message
    puts "This is a private message"
  end
end
irb> Receiver.new.public_message
This is a private message
 => nil
irb> Receiver.new.self_public_message
NoMethodError: private method `private_message' called for #<Receiver:0x007b>
irb> Receiver.new.private_message
NoMethodError: private method `private_message' called for #<Receiver:0x007b>

上面的代码中,在 Receiver#public_message 方法内部,Receiver 实例隐式的发送了私有的消息 private_message 给接收器 self。因为我们处于 Receiver 上下文中,而且消息接收器是隐式的 ( self ) ,因此 Receiver#private_message 是可以响应此消息的。

Receiver#self_public_messsage 则明确的调用了接收器 self 的私有方法。因为私有的消息处理器无法响应此接收器,所以会抛出 NoMethodError 异常。

Receiver.new.private_message 的显式调用将引发 NoMethodError ,因为该消息是从private_message 上下文(应该是 Receiver 的实例)外部发送的。

受保护 ( protected ) 方法

在 Ruby 中,受保护的方法( 或受保护的消息处理程序 )只能响应具有同族的隐式/显式接收器( 对象 )的消息。它也无法响应从受保护的消息处理程序上下文外部发送的消息

class Receiver
  def public_message
    protected_message
  end
  def self_public_message
    self.protected_message
  end
  protected
  def protected_message
    puts "This is a protected message"
  end
end
class Mailbox < Receiver
  def mb_public_message
    ::Mailbox.new.protected_message
  end
end
irb> Receiver.new.public_message
This is a protected message
=> nil
irb> Receiver.new.self_public_message
This is a protected message
=> nil
irb> Mailbox.new.mb_public_message
This is a protected message
=> nil
irb> Receiver.new.protected_message
NoMethodError: protected method `protected_message' called for #<Receiver:0x007fbed691bdf0>

Receiver#public_message 方法中,protectedprivate 方法共享相同的策略

Receiver#self_public_message 显式调用接收者 self 的受保护方法,因此受保护的消息处理程序 Receiver#protected_message 可以响应消息,因为它包含

  • 同族 ( 在一个继承体系内 ) 的接收器
  • 消息由 Receiver 对象发送

Mailbox.new.mb_public_method 方法也可以正常工作,原因与上面列举的相同

但,Receiver.new.protected_message 则会引发 NoMethodError 异常,因为消息是从 Receiver 对象外部发送的

## Kernel#send 方法

Kernel#send 方法的某个特性在一定的条件下 ( 比如测试 ) 是非常有用的。这个特性就是:

当使用此方法发送消息时,将绕过私有策略和受保护策略

ruby class Receiver def public_message protected_message end def self_public_message self.protected_message end protected def protected_message puts "This is a protected message" end private def private_message puts "this is a private message" end end irb> Receiver.new.send(:private_message) this is a private message => nil irb> Receiver.new.send(:protected_message) This is a protected message => nil

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2018 简单教程 twle.cn All Rights Reserved.