التفويض باستخدام 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. يحتفظ بالأغاني في @songs، وكل أغنية زوج من الشكل [title, seconds]. مرّر استدعاءات 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)}"
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت