Menu
Coddy logo textTech

Metodi protetti

Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 18 di 57.

Un metodo protetto si colloca tra pubblico e privato. Il codice esterno non può chiamarlo, ma qualsiasi oggetto della stessa classe può chiamarlo su un altro oggetto. Questo permette a due oggetti di confrontare dati che non mostrano al resto del programma:

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

Output:

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

La differenza rispetto a private si nota quando il ricevente è un altro oggetto. other.balance funziona per un metodo protetto e non funziona per uno privato:

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)

Output:

3
private refused other.hidden

protected funziona anche con attr_reader, il modo usuale per condividere un valore solo tra oggetti di una stessa classe, ad esempio per decidere quale di due oggetti vince:

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

Output:

true
["Ada"]

Scegli il livello più restrittivo che funziona. public è per l’interfaccia della classe, protected per i dati che gli oggetti della classe confrontano tra loro e private per tutto il resto:

public      # chiunque: order.total
protected   # oggetti della classe: other.balance all'interno di Account
private     # solo l'oggetto stesso: subtotal, self.subtotal
challenge icon

Sfida

Facile

Completa la classe Account. Il saldo è leggibile solo dagli altri account: rendi protetto il relativo accessor. richer_than?(other) confronta i saldi, transfer_to(other, amount) trasferisce denaro a un altro account tramite il metodo protetto dell'altro account receive(amount) e restituisce true, oppure restituisce false quando il saldo è insufficiente. to_s restituisce solo il nome del proprietario.

Il codice fornito legge i nomi dei due proprietari e i rispettivi saldi, poi i comandi transfer a b 50, stampando ok oppure refused. Poi stampa Ada is richer (oppure Bo is richer, oppure equal) e infine prova a leggere balance dall'esterno, stampando balance is protected quando Ruby rifiuta.

Il tuo codice va in account.rb. main.rb contiene il codice fornito per input/output e non può essere modificato.

Provalo tu

require_relative 'account'

# Supplied input/output code: keep it as it is
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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Ruby online