Menu
CoddyTech

סַטֶּרִים פרטיים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 19 מתוך 57.

לעיתים קרובות צריך שכולם יוכלו לקרוא ערך, אבל רק האובייקט יוכל לשנות אותו. attr_reader מספק קורא ציבורי, ו-private attr_writer מספק מגדיר ערך שרק האובייקט יכול להשתמש בו. זה עובד מפני ש-attr_writer מחזיר את שמות המתודות שהוא מגדיר:

class Wallet
  attr_reader :balance

  def initialize
    self.balance = 0
  end

  def earn(amount)
    self.balance = balance + amount
  end

  private attr_writer :balance
end

w = Wallet.new
w.earn(30)
puts w.balance
begin
  w.balance = 1_000_000
rescue NoMethodError => e
  puts e.message
end

פלט:

30
private method `balance=' called for an instance of Wallet

ל־setter פרטי קוראים עם self. בתוך המחלקה, זהו המקבל היחיד ש־Ruby מאפשרת עבור מתודות פרטיות. בלי self. ההשמה הייתה יוצרת רק משתנה מקומי:

class Lamp
  attr_reader :on

  def initialize
    self.on = false
  end

  def toggle
    self.on = !on
    self
  end

  private

  attr_writer :on
end

puts Lamp.new.toggle.toggle.toggle.on

פלט:

true

שימוש במגדיר ערך פרטי במקום להקצות ישירות ל־@balance משאיר מקום אחד לכללים, כמו בדיקה שהערך תקין:

class Tank
  attr_reader :litres

  def initialize(capacity)
    @capacity = capacity
    self.litres = 0
  end

  def fill(amount)
    self.litres = litres + amount
  end

  def drain(amount)
    self.litres = litres - amount
  end

  private

  def litres=(value)
    @litres = value.clamp(0, @capacity)
  end
end

t = Tank.new(50)
t.fill(80)
puts t.litres
t.drain(70)
puts t.litres

פלט:

50
0

private attr_accessor :history מסתיר גם את הקורא וגם את הקובע, עבור מצב פנימי שקוד חיצוני לא אמור אפילו לראות:

class Editor
  def initialize
    self.history = []
  end

  def type(text)
    history << text
  end

  private attr_accessor :history
end
challenge icon

אתגר

קל

השלימו את המחלקה Wallet. אפשר לקרוא את balance מבחוץ, אבל אפשר להגדיר אותו רק באמצעות מתודת הגדרה פרטית, והוא מתחיל ב־0. הפונקציה earn(amount) מוסיפה לו. הפונקציה spend(amount) מחסירה ממנו ומחזירה true, או מחזירה false ללא שינוי כשהיתרה נמוכה מדי. history מחזיר את מספר השינויים המוצלחים, וגם הוא נשמר מאחורי מתודת הגדרה פרטית.

הקוד שסופק קורא פקודות +n או -n, ומדפיס balance 30 אחרי כל אחת מהן, או declined כשפעולת הוצאה נכשלת. לאחר מכן הוא מדפיס changes: 2 ומנסה לבצע wallet.balance = 1000000, ומדפיס cannot set balance כש־Ruby מסרבת.

הקוד שלכם ייכתב בקובץ wallet.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.

נסו בעצמכם

require_relative 'wallet'

# קוד קלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
  input << line.chomp
end
wallet = Wallet.new
input.each do |cmd|
  amount = cmd[1..].to_i
  if cmd.start_with?("+")
    wallet.earn(amount)
    puts "balance #{wallet.balance}"
  elsif wallet.spend(amount)
    puts "balance #{wallet.balance}"
  else
    puts "declined"
  end
end
puts "changes: #{wallet.history}"
begin
  wallet.balance = 1_000_000
  puts "balance set"
rescue NoMethodError
  puts "cannot set balance"
end
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Ruby אונליין