Asignadores privados
Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 19 de 57.
A menudo, un valor debería ser legible para todos, pero modificable solo por el objeto. attr_reader proporciona el lector público, y private attr_writer un setter que solo puede usar el objeto. Esto funciona porque attr_writer devuelve los nombres de los métodos que define:
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
endSalida:
30
private method `balance=' called for an instance of WalletSe llama a un setter privado con self. dentro de la clase, el único receptor que Ruby acepta para los métodos privados. Sin self., la asignación solo crearía una variable local:
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.onSalida:
truePasar por un establecedor privado en lugar de asignar directamente @balance mantiene las reglas en un solo lugar, como una comprobación de que el valor sea válido:
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.litresSalida:
50
0private attr_accessor :history oculta tanto el lector como el setter, para un estado interno que el código externo ni siquiera debería ver:
class Editor
def initialize
self.history = []
end
def type(text)
history << text
end
private attr_accessor :history
endDesafío
FácilCompleta la clase Wallet. balance se puede leer desde fuera, pero solo se establece mediante un setter privado y comienza en 0. earn(amount) lo incrementa. spend(amount) lo disminuye y devuelve true, o devuelve false sin hacer cambios cuando el saldo es demasiado bajo. history devuelve el número de cambios exitosos y también se mantiene detrás de un setter privado.
El código proporcionado lee comandos +n o -n e imprime balance 30 después de cada uno, o declined cuando falla un gasto. Después imprime changes: 2 e intenta wallet.balance = 1000000, e imprime cannot set balance cuando Ruby lo rechaza.
Tu código va en wallet.rb. main.rb contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
require_relative 'wallet'
# Código de entrada/salida proporcionado: mantenlo 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
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
1Clases y objetos
Trabajar con archivosDefinir clasesVariables de instanciaMétodos y selfto_s e inspectRepaso: tarjeta de biblioteca4Encapsulación
Métodos privadosMétodos protegidosAsignadores privadosProtección del estadoRepaso: máquina expendedora7Polimorfismo y tipado pato
PolimorfismoTipado patoMétodos abstractoscase y clasesRepaso: métodos de pago2Accesores y self
Lectores y escritoresSetters personalizadosself en los métodosIdentidad e igualdadRepaso: lista de contactos5Herencia
SubclasesSobrescritura de métodosLlamar a superis_a? y ancestrosRepaso - Nómina del personal8Métodos especiales
Igualdad y hashMétodos de operadoresIndexación y adiciónColecciones personalizadasRepaso: fracciones11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de Ruby online