Menu
Coddy logo textTech

Métodos protegidos

Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 18 de 57.

Un método protected se encuentra entre lo público y lo privado. El código externo no puede llamarlo, pero cualquier objeto de la misma clase puede llamarlo sobre otro objeto. Esto permite que dos objetos comparen datos que no muestran al resto del programa:

class Account
  def initialize(owner, balance)
    @owner = owner
    @balance = balance
  end

  def richer_than?(other)
    balance > other.balance
  end

  protected

  def balance
    @balance
  end
end

ada = Account.new("Ada", 500)
bo = Account.new("Bo", 300)
puts ada.richer_than?(bo)
begin
  ada.balance
rescue NoMethodError => e
  puts e.message
end

Salida:

true
protected method `balance' called for an instance of Account

La diferencia con private se manifiesta cuando el receptor es otro objeto. other.balance funciona para un método protegido y falla para uno privado:

class Sample
  def initialize(n)
    @n = n
  end

  def compare_protected(other)
    other.guarded + guarded
  end

  def compare_private(other)
    other.hidden + hidden
  rescue NoMethodError
    "private refused other.hidden"
  end

  protected

  def guarded
    @n
  end

  private

  def hidden
    @n
  end
end

a = Sample.new(1)
b = Sample.new(2)
puts a.compare_protected(b)
puts a.compare_private(b)

Salida:

3
private refused other.hidden

protected también funciona con attr_reader, la forma habitual de compartir un valor únicamente entre objetos de una clase, por ejemplo, para decidir cuál de dos objetos gana:

class Player
  attr_reader :name

  def initialize(name, rating)
    @name = name
    @rating = rating
  end

  def stronger?(other)
    rating > other.rating
  end

  protected

  attr_reader :rating
end

a = Player.new("Ada", 1200)
b = Player.new("Bo", 1100)
puts a.stronger?(b)
puts [a, b].select { |pl| pl.stronger?(b) }.map(&:name).inspect

Salida:

true
["Ada"]

Elige el nivel más restringido que funcione. public es para la interfaz de la clase, protected para los datos que los objetos de la clase comparan entre sí y private para todo lo demás:

public      # cualquiera: order.total
protected   # objetos de la clase: other.balance dentro de Account
private     # solo el objeto mismo: subtotal, self.subtotal
challenge icon

Desafío

Fácil

Completa la clase Account. El saldo solo debe poder ser leído por otras cuentas: haz que su lector sea protected. richer_than?(other) compara los saldos, transfer_to(other, amount) transfiere dinero a otra cuenta mediante el método protected de la otra cuenta, receive(amount), y devuelve true, o devuelve false cuando el saldo es demasiado bajo. to_s devuelve únicamente el nombre del propietario.

El código proporcionado lee los dos propietarios y sus saldos, después los comandos transfer a b 50, e imprime ok o refused. Después imprime Ada is richer (o Bo is richer, o equal) y, finalmente, intenta leer balance desde fuera, imprimiendo balance is protected cuando Ruby lo rechaza.

Tu código debe ir en account.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

require_relative 'account'

# Código de entrada/salida suministrado: déjalo tal como está
input = []
while (line = gets)
  input << line.chomp
end
accounts = input[0..1].map do |line|
  owner, balance = line.split
  Account.new(owner, balance.to_i)
end
a, b = accounts
input.drop(2).each do |line|
  _, from, to, amount = line.split
  source = from == "a" ? a : b
  target = to == "a" ? a : b
  puts source.transfer_to(target, amount.to_i) ? "ok" : "refused"
end
if a.richer_than?(b) then puts "#{a} is richer"
elsif b.richer_than?(a) then puts "#{b} is richer"
else puts "equal"
end
begin
  a.balance
  puts "balance is public"
rescue NoMethodError
  puts "balance is protected"
end
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de Ruby online