מתודות מוגנות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 18 מתוך 57.
מתודה מוגנת נמצאת בין ציבורית לפרטית. קוד חיצוני לא יכול לקרוא לה, אבל כל אובייקט מאותה מחלקה יכול לקרוא לה עבור אובייקט אחר. כך שני אובייקטים יכולים להשוות נתונים שהם לא חושפים לשאר התוכנית:
class Account
def initialize(owner, balance)
@owner = owner
@balance = balance
end
def richer_than?(other)
balance > other.balance
end
protected
def balance
@balance
end
end
ada = Account.new("Ada", 500)
bo = Account.new("Bo", 300)
puts ada.richer_than?(bo)
begin
ada.balance
rescue NoMethodError => e
puts e.message
endפלט:
true
protected method `balance' called for an instance of Accountההבדל לעומת private מתגלה כשהמקבל הוא אובייקט אחר. other.balance עובד עבור מתודה מוגנת ונכשל עבור מתודה פרטית:
class Sample
def initialize(n)
@n = n
end
def compare_protected(other)
other.guarded + guarded
end
def compare_private(other)
other.hidden + hidden
rescue NoMethodError
"private refused other.hidden"
end
protected
def guarded
@n
end
private
def hidden
@n
end
end
a = Sample.new(1)
b = Sample.new(2)
puts a.compare_protected(b)
puts a.compare_private(b)פלט:
3
private refused other.hiddenprotected עובד גם עם attr_reader, הדרך המקובלת לשתף ערך רק בין אובייקטים של אותה מחלקה, למשל כדי להחליט מי משני אובייקטים מנצח:
class Player
attr_reader :name
def initialize(name, rating)
@name = name
@rating = rating
end
def stronger?(other)
rating > other.rating
end
protected
attr_reader :rating
end
a = Player.new("Ada", 1200)
b = Player.new("Bo", 1100)
puts a.stronger?(b)
puts [a, b].select { |pl| pl.stronger?(b) }.map(&:name).inspectפלט:
true
["Ada"]בחרו את רמת הגישה המצומצמת ביותר שעובדת. public מיועדת לממשק של המחלקה, protected לנתונים שאובייקטים של המחלקה משווים ביניהם, ו־private לכל השאר:
public # כל אחד: order.total
protected # אובייקטים של המחלקה: other.balance בתוך Account
private # רק האובייקט עצמו: subtotal, self.subtotalאתגר
קלהשלם את המחלקה Account. אפשר לקרוא את היתרה רק מתוך חשבונות אחרים: הגדר את הקורא שלה כמוגן. richer_than?(other) משווה בין היתרות, transfer_to(other, amount) מעביר כסף לחשבון אחר באמצעות המתודה המוגנת receive(amount) של החשבון האחר ומחזיר true, או מחזיר false כשהיתרה נמוכה מדי. to_s מחזירה רק את שם הבעלים.
הקוד שסופק קורא את שמות שני הבעלים ואת היתרות, ואז קורא פקודות transfer a b 50 ומדפיס ok או refused. לאחר מכן הוא מדפיס Ada is richer (או Bo is richer, או equal) ולבסוף מנסה לקרוא את balance מבחוץ, ומדפיס balance is protected כש-Ruby מסרבת.
הקוד שלך ייכנס ל-account.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
require_relative 'account'
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
input << line.chomp
end
accounts = input[0..1].map do |line|
owner, balance = line.split
Account.new(owner, balance.to_i)
end
a, b = accounts
input.drop(2).each do |line|
_, from, to, amount = line.split
source = from == "a" ? a : b
target = to == "a" ? a : b
puts source.transfer_to(target, amount.to_i) ? "ok" : "refused"
end
if a.richer_than?(b) then puts "#{a} is richer"
elsif b.richer_than?(a) then puts "#{b} is richer"
else puts "equal"
end
begin
a.balance
puts "balance is public"
rescue NoMethodError
puts "balance is protected"
end
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין