Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

التفويض باستخدام 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      # كل method في 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 العناوينَ موصولةً باستخدام , .

يضيف الكود الم 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)}"
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Ruby عبر الإنترنت