Zustand schützen
Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 20 von 57.
Ein Objekt sollte Anfragen ablehnen, die seinen Zustand beeinträchtigen würden. raise beendet die Methode, bevor sich irgendetwas ändert. Der Name deiner eigenen Fehlerklasse bezeichnet das Problem genau; < StandardError macht die Klasse zu einer Fehlerart (Vererbung, Kapitel 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.balanceAusgabe:
InsufficientFunds: only 50 available
50Separate Fehlerklassen ermöglichen es dem Aufrufer, auf jedes Problem unterschiedlich zu reagieren, mit einem rescue pro Klasse. Deklariere Fehlerklassen vor den Klassen, die sie auslösen:
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}"
endAusgabe:
charged 40
fix the input: amount must be positive
try later: limit is 100freeze macht ein Objekt schreibgeschützt: Danach löst jede Änderung an seinen Instanzvariablen FrozenError aus, während das Lesen weiterhin funktioniert. frozen? gibt an, ob ein Objekt eingefroren ist:
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.xAusgabe:
true
FrozenError
1Ein Leser, der ein internes Array zurückgibt, händigt das tatsächliche Array aus, sodass Code außerhalb des Objekts es ändern könnte. Gib eine eingefrorene Kopie mit @items.dup.freeze oder @items.dup zurück, damit das Objekt die Kontrolle über seine eigenen Daten behält:
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.songsAusgabe:
songs are read-only
["Intro"]Aufgabe
EinfachDeklariere die Fehlerklassen InvalidAmount und InsufficientFunds, die beide Unterklassen von StandardError sind, und vervollständige Account. deposit(amount) und withdraw(amount) lösen für Beträge unter 1 InvalidAmount mit amount must be positive aus. withdraw löst InsufficientFunds mit balance is only 20 aus, wenn der Betrag größer als das Guthaben ist. Wenn ein Fehler ausgelöst wird, ändert sich nichts.
Der bereitgestellte Code liest Befehle dep n oder wd n ein und gibt nach jedem Befehl balance 70 aus, bei InvalidAmount invalid: amount must be positive und bei InsufficientFunds refused: balance is only 20.
Dein Code gehört in invalid_amount.rb, insufficient_funds.rb und account.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.
Probier es selbst
require_relative 'invalid_amount'
require_relative 'insufficient_funds'
require_relative 'account'
# Bereitgestellter Ein-/Ausgabe-Code: belasse ihn unverändert
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
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Klassen und Objekte
Arbeiten mit DateienKlassen definierenInstanzvariablenMethoden und selfto_s und inspectRückblick – Bibliotheksausweis4Kapselung
Private MethodenGeschützte MethodenPrivate SetterZustand schützenRückblick – Verkaufsautomat7Polymorphismus und Duck Typing
PolymorphismusDuck TypingAbstrakte MethodenFälle und KlassenRückblick – Zahlungsmethoden2Getter und Setter sowie self
Leser und SchreiberBenutzerdefinierte Setterself in MethodenIdentität und GleichheitWiederholung – Kontaktliste5Vererbung
UnterklassenMethoden überschreibensuper aufrufenis_a? und VorfahrenRückblick – Gehaltsabrechnung des Personals8Spezielle Methoden
Gleichheit und HashOperator-MethodenIndexieren und AnhängenBenutzerdefinierte CollectionsRückblick – Brüche11Projekt: Bibliotheksverwaltung
Bücher und MitgliederBücher ausleihenÜbe selbstständig: Online-Ruby-Compiler