상태 보호
Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 20번째.
객체는 자신의 상태를 깨뜨릴 요청을 거부해야 합니다. raise는 어떤 것도 변경되기 전에 메서드를 중단합니다. 직접 만든 오류 클래스는 문제를 정확하게 명명하며, < StandardError는 이 클래스가 오류의 한 종류가 되도록 합니다(상속, 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.balance출력:
InsufficientFunds: only 50 available
50별도의 오류 클래스를 사용하면 호출자는 각 문제에 대해 하나의 클래스당 하나의 rescue를 사용하여 서로 다르게 대응할 수 있습니다. 오류를 발생시키는 클래스보다 먼저 오류 클래스를 선언하세요.
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}"
end출력:
charged 40
fix the input: amount must be positive
try later: limit is 100freeze는 객체를 읽기 전용으로 만듭니다. 이를 적용한 후 인스턴스 변수에 변경을 가하면 FrozenError가 발생하지만, 읽기는 계속 작동합니다. frozen?은 객체가 동결되었는지 알려 줍니다:
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.x출력:
true
FrozenError
1내부 배열을 반환하는 리더는 실제 배열을 그대로 넘겨주므로 외부 코드가 배열을 변경할 수 있습니다. @items.dup.freeze 또는 @items.dup을 사용해 동결된 복사본을 반환하면 객체가 자체 데이터를 직접 제어할 수 있습니다:
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.songs출력:
songs are read-only
["Intro"]챌린지
쉬움오류 클래스 InvalidAmount와 InsufficientFunds를 선언하세요. 두 클래스 모두 StandardError의 하위 클래스이며, Account를 완성하세요. deposit(amount)와 withdraw(amount)는 1 미만인 금액에 대해 amount must be positive 메시지와 함께 InvalidAmount를 발생시킵니다. 금액이 잔액보다 클 때 withdraw는 balance is only 20 메시지와 함께 InsufficientFunds를 발생시킵니다. 오류가 발생하면 아무것도 변경되지 않습니다.
제공된 코드는 dep n 또는 wd n 명령을 읽고, 각 명령 후에 balance 70을 출력합니다. InvalidAmount에 대해서는 invalid: amount must be positive를, InsufficientFunds에 대해서는 refused: balance is only 20을 출력합니다.
코드는 invalid_amount.rb, insufficient_funds.rb, account.rb에 작성하세요. main.rb에는 제공된 입출력 코드가 들어 있으며 수정할 수 없습니다.
직접 해보기
require_relative 'invalid_amount'
require_relative 'insufficient_funds'
require_relative 'account'
# 제공된 입력/출력 코드: 그대로 유지하세요
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
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Ruby 컴파일러