Menu
Coddy logo textTech

האצלה באמצעות Forwardable

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

האצלה פירושה שאובייקט מעביר חלק מעבודתו לאובייקט שהוא מכיל, במקום לרשת ממנו. רשימת השמעה שיש לה מערך של שירים בטוחה יותר מרשימת השמעה שהיא מערך, מפני שקוד חיצוני מקבל רק את המתודות שתבחר להעביר אליו:

class Playlist
  def initialize
    @songs = []
  end

  def add(song)
    @songs << song
    self
  end

  def size
    @songs.size
  end

  def first
    @songs.first
  end
end

list = Playlist.new.add("Intro").add("Dune")
puts list.size
puts list.first

פלט:

2
Intro

כתיבת כל שיטת העברה באופן ידני היא חזרתית. הספרייה הסטנדרטית Forwardable עושה זאת: extend Forwardable, ואז def_delegators :@songs, :size, :first מעבירה את הקריאות האלה לאובייקט שב־@songs:

require 'forwardable'

class Playlist
  extend Forwardable
  def_delegators :@songs, :size, :first, :last, :empty?, :include?

  def initialize
    @songs = []
  end

  def add(song)
    @songs << song
    self
  end
end

list = Playlist.new.add("Intro").add("Dune")
puts "#{list.size} #{list.first} #{list.last}"
puts list.include?("Dune")
puts list.empty?

פלט:

2 Intro Dune
true
false

def_delegator :@songs, :push, :add מעביר שיטה אחת תחת שם חדש. האובייקט שומר על שליטה מלאה בכל מה שהוא לא מעביר, למשל delete או clear:

require 'forwardable'

class Queue2
  extend Forwardable
  def_delegator :@jobs, :push, :enqueue
  def_delegator :@jobs, :shift, :next_job
  def_delegators :@jobs, :size

  def initialize
    @jobs = []
  end
end

q = Queue2.new
q.enqueue("a")
q.enqueue("b")
puts q.next_job
puts q.size
puts q.respond_to?(:clear)

פלט:

a
1
false

העדיפו האצלה ("יש לו") כאשר מחלקה זקוקה רק לחלק מההתנהגות של מחלקה אחרת. ירושה מ־Array תחשוף עשרות שיטות, כמו clear ו־delete_at, שעלולות להפר את הכללים של רשימת ההשמעה:

class Playlist < Array      # כל המתודות של Array הן ציבוריות, כולל clear
end

class Playlist              # רק מה שמעבירים הלאה הוא ציבורי
  extend Forwardable
  def_delegators :@songs, :size, :each
end
challenge icon

אתגר

קל

השלימו את המחלקה Playlist באמצעות Forwardable. היא מכילה שירים, שכל אחד מהם הוא זוג [title, seconds], בתוך @songs. העבירו את size, את empty? ואת first באמצעות def_delegators, והעבירו את push בשם add באמצעות def_delegator. המתודה שלה duration מחזירה את האורך הכולל בפורמט m:ss, והמתודה titles מחזירה את הכותרות כשהן מחוברות באמצעות , .

הקוד שסופק מוסיף שיר עבור כל שורת קלט (title,seconds) באמצעות add, ואז מדפיס את הגודל, את הכותרת הראשונה, את הכותרות, את משך הזמן והאם רשימת ההשמעה מגיבה ל־clear.

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

נסו בעצמכם

require_relative 'playlist'

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
  input << line.chomp
end
list = Playlist.new
input.each do |line|
  title, seconds = line.split(",")
  list.add([title, seconds.to_i])
end
puts "songs: #{list.size}"
puts "first: #{list.empty? ? "none" : list.first[0]}"
puts "titles: #{list.titles}"
puts "duration: #{list.duration}"
puts "can clear: #{list.respond_to?(:clear)}"
quiz iconבחנו את עצמכם

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

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

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