האצלה באמצעות 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
falsedef_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אתגר
קלהשלימו את המחלקה 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)}"
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין