Ochrona stanu
Część sekcji Programowanie obiektowe ścieżki Ruby w Coddy. Lekcja 20 z 57.
Obiekt powinien odrzucać żądania, które naruszyłyby jego stan. raise zatrzymuje metodę, zanim cokolwiek się zmieni. Nazwa własnej klasy błędu precyzyjnie określa problem; < StandardError sprawia, że ta klasa jest rodzajem błędu (dziedziczenie, rozdział 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.balanceWynik:
InsufficientFunds: only 50 available
50Osobne klasy błędów pozwalają wywołującemu reagować na każdy problem inaczej, używając jednego bloku rescue dla każdej klasy. Zadeklaruj klasy błędów przed klasami, które je zgłaszają:
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}"
endWynik:
charged 40
fix the input: amount must be positive
try later: limit is 100freeze zmienia obiekt w obiekt tylko do odczytu: po jego wywołaniu każda zmiana zmiennych instancji powoduje zgłoszenie wyjątku FrozenError, a odczyt nadal działa. frozen? informuje, czy obiekt jest zamrożony:
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.xWynik:
true
FrozenError
1Czytnik, który zwraca wewnętrzną tablicę, udostępnia prawdziwą tablicę, więc kod zewnętrzny może ją zmienić. Zwróć zamrożoną kopię za pomocą @items.dup.freeze albo @items.dup, aby obiekt zachował kontrolę nad własnymi danymi:
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.songsWynik:
songs are read-only
["Intro"]Wyzwanie
ŁatwyZadeklaruj klasy błędów InvalidAmount i InsufficientFunds, obie będące podklasami StandardError, i uzupełnij klasę Account. Metody deposit(amount) i withdraw(amount) zgłaszają wyjątek InvalidAmount z komunikatem amount must be positive dla kwot mniejszych niż 1. Metoda withdraw zgłasza wyjątek InsufficientFunds z komunikatem balance is only 20, gdy kwota jest większa niż saldo. W przypadku zgłoszenia błędu nic się nie zmienia.
Dostarczony kod odczytuje polecenia dep n lub wd n i po każdym wyświetla balance 70, invalid: amount must be positive dla InvalidAmount oraz refused: balance is only 20 dla InsufficientFunds.
Twój kod umieść w plikach invalid_amount.rb, insufficient_funds.rb i account.rb. Plik main.rb zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
require_relative 'invalid_amount'
require_relative 'insufficient_funds'
require_relative 'account'
# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Klasy i obiekty
Praca z plikamiDefiniowanie klasZmienne instancjiMetody i selfto_s i inspectPowtórzenie – karta biblioteczna4Hermetyzacja
Metody prywatneMetody chronionePrywatne setteryOchrona stanuPowtórzenie – automat vendingowy7Polimorfizm i typowanie kacze
PolimorfizmTypowanie kaczeMetody abstrakcyjnecase i klasyPowtórzenie – metody płatności10Wzorce projektowe, część 2
Delegowanie z ForwardableWzorzec dekoratoraWzorzec budowniczegoWzorzec stanu2Metody dostępowe i self
Gettery i setteryWłasne setteryself w metodachTożsamość i równośćPowtórzenie – lista kontaktów5Dziedziczenie
PodklasyNadpisywanie metodWywoływanie superis_a? i przodkowiePowtórka – lista płac pracowników8Metody specjalne
Równość i hashMetody operatorówIndeksowanie i dodawanieWłasne kolekcjePowtórka – ułamki11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książekPoćwicz samodzielnie: Kompilator Ruby online