Menu
Coddy logo textTech

Setter privati

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

Spesso un valore dovrebbe essere leggibile da tutti, ma modificabile solo dall'oggetto. attr_reader fornisce il lettore pubblico, mentre private attr_writer un setter che può usare solo l'oggetto. Questo funziona perché attr_writer restituisce i nomi dei metodi che definisce:

class Wallet
  attr_reader :balance

  def initialize
    self.balance = 0
  end

  def earn(amount)
    self.balance = balance + amount
  end

  private attr_writer :balance
end

w = Wallet.new
w.earn(30)
puts w.balance
begin
  w.balance = 1_000_000
rescue NoMethodError => e
  puts e.message
end

Output:

30
private method `balance=' called for an instance of Wallet

Un setter privato viene chiamato con self. all’interno della classe, l’unico ricevente che Ruby accetta per i metodi privati. Senza self. l’assegnazione creerebbe solo una variabile locale:

class Lamp
  attr_reader :on

  def initialize
    self.on = false
  end

  def toggle
    self.on = !on
    self
  end

  private

  attr_writer :on
end

puts Lamp.new.toggle.toggle.toggle.on

Output:

true

Passare attraverso un setter privato invece di assegnare direttamente @balance mantiene le regole in un unico punto, come un controllo che il valore sia valido:

class Tank
  attr_reader :litres

  def initialize(capacity)
    @capacity = capacity
    self.litres = 0
  end

  def fill(amount)
    self.litres = litres + amount
  end

  def drain(amount)
    self.litres = litres - amount
  end

  private

  def litres=(value)
    @litres = value.clamp(0, @capacity)
  end
end

t = Tank.new(50)
t.fill(80)
puts t.litres
t.drain(70)
puts t.litres

Output:

50
0

private attr_accessor :history nasconde sia il metodo di lettura sia il setter, per uno stato interno che il codice esterno non dovrebbe nemmeno vedere:

class Editor
  def initialize
    self.history = []
  end

  def type(text)
    history << text
  end

  private attr_accessor :history
end
challenge icon

Sfida

Facile

Completa la classe Wallet. balance è leggibile dall’esterno ma può essere impostato solo tramite un setter privato, con valore iniziale 0. earn(amount) lo incrementa. spend(amount) lo decrementa e restituisce true, oppure restituisce false senza apportare modifiche quando il saldo è troppo basso. history restituisce il numero di modifiche riuscite, ed è anch’esso protetto da un setter privato.

Il codice fornito legge i comandi +n o -n, stampando balance 30 dopo ciascuno, oppure declined quando una spesa non riesce. Poi stampa changes: 2 e prova wallet.balance = 1000000, stampando cannot set balance quando Ruby rifiuta.

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

Provalo tu

require_relative 'wallet'

# Código de entrada/salida proporcionado: déjalo tal como está
input = []
while (line = gets)
  input << line.chomp
end
wallet = Wallet.new
input.each do |cmd|
  amount = cmd[1..].to_i
  if cmd.start_with?("+")
    wallet.earn(amount)
    puts "balance #{wallet.balance}"
  elsif wallet.spend(amount)
    puts "balance #{wallet.balance}"
  else
    puts "declined"
  end
end
puts "changes: #{wallet.history}"
begin
  wallet.balance = 1_000_000
  puts "balance set"
rescue NoMethodError
  puts "cannot set balance"
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