ZetCode

Ruby 受保护方法

最后修改日期:2025 年 4 月 27 日

本教程深入介绍了 Ruby 的 protected 方法可见性。受保护的方法提供对相关对象之间的受控访问。

protected 可见性允许方法只能由同一类或其子类的对象调用。它介于 public 和 private 访问之间。

受保护的方法能够在类层次结构内实现受控共享。它们通常用于内部比较和辅助方法。

基本的受保护方法示例

此示例演示了基本的受保护方法行为。该方法在类层次结构内可访问,但在外部不可访问。

basic_protected.rb
class Person
  protected
  
  def greet
    "Hello from protected method"
  end
end

class Employee < Person
  def call_greet
    greet  # Works - same class hierarchy
  end
end

person = Person.new
# person.greet  # Error - protected method called

employee = Employee.new
puts employee.call_greet  # Works through public method

greet 方法是受保护的,因此不能直接在 person 上调用。但是,Employee 可以通过其自身的公共方法访问它。

用于对象比较的受保护方法

受保护的方法非常适合比较同一类的对象。此示例显示了两个 Account 对象之间的受保护访问。

account_comparison.rb
class Account
  attr_reader :balance
  
  def initialize(balance)
    @balance = balance
  end
  
  def >(other_account)
    balance > other_account.balance
  end
  
  protected :balance
end

account1 = Account.new(1000)
account2 = Account.new(500)

puts account1 > account2  # true
# puts account1.balance  # Error - protected method

balance 读取器是受保护的,它允许在 Account 对象之间进行比较,同时阻止直接访问。这有助于保持封装。

类层次结构中的受保护访问

此示例展示了类层次结构中跨类的受保护方法访问。子类可以访问父类的受保护方法。

class_hierarchy.rb
class Vehicle
  protected
  
  def engine_details
    "V6 Turbo Engine"
  end
end

class Car < Vehicle
  def show_engine
    "Car has: #{engine_details}"
  end
end

class Truck < Vehicle
  def show_engine
    "Truck has: #{engine_details}"
  end
end

car = Car.new
puts car.show_engine

truck = Truck.new
puts truck.show_engine

CarTruck 都可以访问其父类的受保护的 engine_details 方法。这促进了代码重用,同时控制了访问。

带有 self 的受保护方法

如果接收者是同一类型的对象,则可以使用显式接收者来调用受保护的方法。此示例使用 self 演示了受保护的方法调用。

self_receiver.rb
class BankAccount
  def initialize(balance)
    @balance = balance
  end
  
  def transfer(other_account, amount)
    if valid_transfer?(other_account, amount)
      deduct(amount)
      other_account.add(amount)
    end
  end
  
  protected
  
  def valid_transfer?(other_account, amount)
    amount > 0 && @balance >= amount
  end
  
  def add(amount)
    @balance += amount
  end
  
  def deduct(amount)
    @balance -= amount
  end
end

account1 = BankAccount.new(1000)
account2 = BankAccount.new(500)

account1.transfer(account2, 200)

受保护的方法 adddeduct 可以调用其他 BankAccount 实例。这使得安全的互对象操作成为可能,同时防止外部访问。

受保护方法与私有方法

此示例对比了受保护方法和私有方法的行为。关键区别在于接收者处理方式。

protected_vs_private.rb
class Test
  def call_protected(other)
    other.protected_method
  end
  
  def call_private(other)
    other.private_method  # Error - private method
  end
  
  protected
  
  def protected_method
    "Protected called"
  end
  
  private
  
  def private_method
    "Private called"
  end
end

test1 = Test.new
test2 = Test.new

puts test1.call_protected(test2)  # Works
# test1.call_private(test2)  # Fails

受保护的方法允许使用同一类的显式接收者,而私有方法则不允许。这是它们之间的根本区别。

受保护的类方法

受保护的可见性也可以应用于类方法。此示例展示了受保护的类方法用法。

protected_class_method.rb
class Configuration
  class << self
    protected
    
    def database_settings
      { adapter: 'postgresql', host: 'localhost' }
    end
  end
  
  def self.get_settings
    database_settings  # Accessible within class
  end
end

puts Configuration.get_settings
# Configuration.database_settings  # Error - protected method

受保护的类方法 database_settings 在类内部是可访问的,但在外部不可访问。这种模式对于内部类逻辑很有用。

模块中的受保护方法

受保护的方法在模块中的工作方式类似。此示例演示了包含模块中受保护方法的行为。

module_protected.rb
module Authenticable
  protected
  
  def generate_token
    SecureRandom.hex(20)
  end
end

class User
  include Authenticable
  
  def login
    @token = generate_token
    "Logged in with token: #{@token[0..5]}..."
  end
end

user = User.new
puts user.login
# user.generate_token  # Error - protected method

来自模块的受保护方法 generate_tokenUser 内部是可访问的,但在外部不可访问。这在允许方法共享的同时维护了安全性。

来源

Ruby 方法文档

本教程通过实际示例,展示了 Ruby 的受保护方法可见性,包括对象比较、类层次结构和模块使用。

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已创作了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Ruby 教程