التفويض باستخدام 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 # كل method في 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 العناوينَ موصولةً باستخدام , .
يضيف الكود الم provided أغنيةً لكل سطر إدخال (title,seconds) باستخدام add، ثم يطبع الحجم، والعنوان الأول، والعناوين، والمدة، وما إذا كانت قائمة التشغيل تستجيب لـ clear.
ضع الكود الخاص بك في playlist.rb. يحتوي main.rb على كود الإدخال/الإخراج الم provided ولا يمكن تعديله.
جرّب بنفسك
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)}"
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت