Proteggere lo stato
Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 20 di 57.
Un oggetto dovrebbe rifiutare le richieste che ne comprometterebbero lo stato. raise interrompe il metodo prima che qualcosa cambi. Il nome della tua classe di errore descrive il problema con precisione; < StandardError rende la classe un tipo di errore (ereditarietà, capitolo 5):
class InsufficientFunds < StandardError
end
class Account
attr_reader :balance
def initialize(balance)
@balance = balance
end
def withdraw(amount)
raise InsufficientFunds, "only #{balance} available" if amount > balance
@balance -= amount
end
end
account = Account.new(50)
begin
account.withdraw(80)
rescue InsufficientFunds => e
puts "#{e.class}: #{e.message}"
end
puts account.balanceOutput:
InsufficientFunds: only 50 available
50Classi di errore separate permettono a chi chiama di reagire a ogni problema in modo diverso, con un rescue per classe. Dichiara le classi di errore prima delle classi che le sollevano:
class InvalidAmount < StandardError
end
class LimitReached < StandardError
end
class Card
def charge(amount)
raise InvalidAmount, "amount must be positive" unless amount.positive?
raise LimitReached, "limit is 100" if amount > 100
"charged #{amount}"
end
end
[40, -5, 500].each do |amount|
puts Card.new.charge(amount)
rescue InvalidAmount => e
puts "fix the input: #{e.message}"
rescue LimitReached => e
puts "try later: #{e.message}"
endOutput:
charged 40
fix the input: amount must be positive
try later: limit is 100freeze rende un oggetto di sola lettura: dopo averlo applicato, qualsiasi modifica alle sue variabili di istanza genera FrozenError, mentre la lettura continua a funzionare. frozen? indica se un oggetto è congelato:
class Point
attr_accessor :x
def initialize(x)
@x = x
end
end
pt = Point.new(1).freeze
puts pt.frozen?
begin
pt.x = 2
rescue FrozenError => e
puts e.class
end
puts pt.xOutput:
true
FrozenError
1Un lettore che restituisce un array interno espone l'array reale, quindi il codice esterno potrebbe modificarlo. Restituisci una copia congelata con @items.dup.freeze, oppure @items.dup, per mantenere l'oggetto al controllo dei propri dati:
class Playlist
def initialize
@songs = []
end
def add(song)
@songs << song
end
def songs
@songs.dup.freeze
end
end
list = Playlist.new
list.add("Intro")
begin
list.songs << "Hack"
rescue FrozenError
puts "songs are read-only"
end
p list.songsOutput:
songs are read-only
["Intro"]Sfida
FacileDichiara le classi di errore InvalidAmount e InsufficientFunds, entrambe sottoclassi di StandardError, e completa Account. deposit(amount) e withdraw(amount) sollevano InvalidAmount con amount must be positive per importi inferiori a 1. withdraw solleva InsufficientFunds con balance is only 20 quando l’importo è maggiore del saldo. Quando viene sollevato un errore, non cambia nulla.
Il codice fornito legge i comandi dep n o wd n e stampa balance 70 dopo ciascuno, invalid: amount must be positive per InvalidAmount e refused: balance is only 20 per InsufficientFunds.
Il tuo codice va inserito in invalid_amount.rb, insufficient_funds.rb e account.rb. main.rb contiene il codice fornito per l’input/output e non può essere modificato.
Provalo tu
require_relative 'invalid_amount'
require_relative 'insufficient_funds'
require_relative 'account'
# Código de entrada/salida proporcionado: mantenlo tal como está
input = []
while (line = gets)
input << line.chomp
end
account = Account.new
input.each do |line|
action, amount = line.split
begin
action == "dep" ? account.deposit(amount.to_i) : account.withdraw(amount.to_i)
puts "balance #{account.balance}"
rescue InvalidAmount => e
puts "invalid: #{e.message}"
rescue InsufficientFunds => e
puts "refused: #{e.message}"
end
end
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
1Classi e oggetti
Lavorare con i fileDefinire le classiVariabili d'istanzaMetodi e selfto_s e inspectRipasso - Tessera della biblioteca4Incapsulamento
Metodi privatiMetodi protettiSetter privatiProteggere lo statoRiepilogo - Distributore automatico7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMetodi astratticase e classiRiepilogo - Metodi di pagamento10Pattern di progettazione Parte 2
Delegazione con ForwardablePattern DecoratorPattern BuilderPattern State2Metodi di accesso e self
Metodi di lettura e scritturaSetter personalizzatiself nei metodiIdentità e uguaglianzaRiepilogo - Elenco contatti5Ereditarietà
SottoclassiRidefinizione dei metodiChiamare superis_a? e antenatiRiepilogo - Paghe del personale8Metodi speciali
Uguaglianza e hashMetodi degli operatoriIndicizzazione e appendCollezioni personalizzateRiepilogo - Frazioni11Progetto: Gestione della biblioteca
Libri e iscrittiPrendere in prestito i libriEsercitati da solo: Compilatore Ruby online