Menu
CoddyTech

האצלה באמצעות 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 אונליין