הגנה על מצב האובייקט
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 20 מתוך 57.
אובייקט אמור לסרב לבקשות שישברו את המצב שלו. 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) מעלות את InvalidAmount עם amount must be positive עבור סכומים הקטנים מ־1. המתודה withdraw מעלה את InsufficientFunds עם balance is only 20 כאשר הסכום גדול מהיתרה. דבר אינו משתנה כאשר מועלת שגיאה.
הקוד שסופק קורא פקודות dep n או wd n ומדפיס balance 70 אחרי כל אחת מהן, invalid: amount must be positive עבור InvalidAmount ו־refused: balance is only 20 עבור InsufficientFunds.
הקוד שלך צריך להופיע בקבצים 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
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין