Setters privados
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 19 de 57.
Frequentemente, um valor deve ser legível por todos, mas alterável apenas pelo objeto. attr_reader fornece o leitor público, e private attr_writer, um setter que somente o objeto pode usar. Isso funciona porque attr_writer retorna os nomes dos 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
endSaída:
30
private method `balance=' called for an instance of WalletUm setter privado é chamado com self. dentro da classe, o único receptor que o Ruby aceita para métodos privados. Sem self., a atribuição apenas criaria uma variável 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.onSaída:
truePassar por um setter privado em vez de atribuir @balance diretamente mantém as regras em um só lugar, como uma verificação de que o valor é 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.litresSaída:
50
0private attr_accessor :history oculta tanto o leitor quanto o setter, para um estado interno que o código externo nem deveria ver:
class Editor
def initialize
self.history = []
end
def type(text)
history << text
end
private attr_accessor :history
endDesafio
FácilComplete a classe Wallet. balance pode ser lido externamente, mas só pode ser definido por meio de um setter privado, começando em 0. earn(amount) adiciona a ele. spend(amount) subtrai e retorna true, ou retorna false sem fazer alterações quando o saldo é insuficiente. history retorna o número de alterações bem-sucedidas, também mantido por trás de um setter privado.
O código fornecido lê comandos +n ou -n, imprimindo balance 30 após cada um, ou declined quando um gasto falha. Em seguida, imprime changes: 2 e tenta wallet.balance = 1000000, imprimindo cannot set balance quando Ruby recusa.
Seu código deve estar em wallet.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'wallet'
# Código de entrada/saída fornecido: mantenha-o 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 lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online