הגנה על מצב האובייקט
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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 אונליין