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 únicamente 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 WalletUn setter privado se invoca 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:
trueUsar un setter privado en lugar de asignar @balance directamente mantiene las reglas en un solo lugar, como una comprobación de que el valor es 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, comenzando en 0. earn(amount) le suma una cantidad. spend(amount) resta una cantidad y devuelve true, o devuelve false sin realizar ningún cambio cuando el saldo es demasiado bajo. history devuelve el número de cambios realizados correctamente 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 un gasto falla. Después imprime changes: 2 e intenta ejecutar wallet.balance = 1000000, imprimiendo cannot set balance cuando Ruby lo rechaza.
Tu código va en wallet.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
require_relative 'wallet'
# Código de entrada/salida suministrado: déjalo 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