Menu
Coddy logo textTech

상태 보호

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 100

freeze는 객체를 읽기 전용으로 만듭니다. 이를 적용한 후 인스턴스 변수에 변경을 가하면 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"]
challenge icon

챌린지

쉬움

오류 클래스 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
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Ruby 컴파일러