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

التفويض (Delegation)

جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy. الدرس 50 من 70.

إن تخزين object داخل object آخر ليس سوى الخطوة الأولى. تأتي القوة الحقيقية للتركيب من التفويض، عندما يمرّر object الخارجي استدعاءات method إلى مكوّناته inner.

فكّر في تشغيل سيارة. لا تمدّ يدك تحت غطاء المحرك وتدير المحرّك يدويًا. بدلًا من ذلك، تدير المفتاح، وتتولى السيارة الباقي داخليًا.

في الشيفرة، يعني هذا أن Car class توفّر طريقة :start() بسيطة تُنفّذ delegates العمل الفعلي إلى engine:

function Car:start()
    print("Turning the key...")
    self.engine:run()  -- فوّض إلى الكائن الداخلي
end

لا تحتاج السيارة إلى معرفة كيفية عمل المحرك. فهي تخبر المحرك فقط بأن يؤدي وظيفته. وهذا يُبقي المسؤوليات منفصلة. تتولى الفئة Engine منطق المحرك، بينما تنسّق Car الأجزاء:

function Engine:run()
    print("Engine running at " .. self.horsepower .. " HP")
end

local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- المخرجات:
-- تدوير المفتاح...
-- المحرك يعمل بقوة 250 حصان

ينشئ التفويض واجهةً واضحةً لمستخدمي class الخاص بك. فهم يتفاعلون مع car، وليس مع أجزائها الداخلية. إذا استبدلت لاحقًا تنفيذًا مختلفًا لـ engine، فستظل الواجهة العامة لـ car كما هي: سيتغير التفويض الداخلي فقط.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لمشغّل موسيقى يوضّح التفويض! ستنشئ مكوّن Speaker وMusicPlayer يحتوي عليه. لن يتولى المشغّل إخراج الصوت مباشرةً، بل سيفوّض هذه المسؤولية إلى speaker الداخلي الخاص به.

ستنظّم التعليمات البرمجية عبر ثلاثة ملفات:

  • Speaker.lua: أنشئ فئة Speaker مع مُنشئ :new(volume) يخزّن مستوى الصوت. أدرج أسلوب :playSound(trackName) يطبع: Playing "{trackName}" at volume {volume}
  • MusicPlayer.lua: أنشئ فئة MusicPlayer whose constructor :new(brand, speaker) تقبل اسم العلامة التجارية وكائن Speaker. يخزّن المشغّل speaker داخله. أدرج الأساليب التالية:
    • :play(trackName): يطبع {brand} player starting... ثم يفوّض إلى أسلوب :playSound() الخاص بـspeaker
    • :stop(): يطبع {brand} player stopped
  • main.lua: اجمع كل شيء معًا! اقرأ المدخلات الخاصة بمستوى صوت speaker، والعلامة التجارية للمشغّل، واسم مقطع موسيقي. أنشئ Speaker أولًا، ثم مرّره إلى مُنشئ MusicPlayer. استدعِ أسلوب :play() الخاص بالمشغّل مع اسم المقطع، ثم استدعِ :stop().

ستتلقى ثلاثة مدخلات:

  1. مستوى صوت speaker (رقم)
  2. العلامة التجارية لمشغّل الموسيقى (سلسلة نصية)
  3. اسم المقطع الموسيقي المراد تشغيله (سلسلة نصية)

يجب أن يُظهر الناتج تنسيق المشغّل للعمل بالتعاون مع speaker الخاص به:

{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stopped

على سبيل المثال، إذا كانت المدخلات هي 75 وSoundMax وSummer Vibes، فيجب أن يكون الناتج:

SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stopped

لاحظ أن MusicPlayer لا يعرف كيف يُنتج الصوت. إنه يخبر speaker ببساطة أن يتولى ذلك الجزء. هذا هو التفويض أثناء العمل: يوفّر الكائن الخارجي واجهة واضحة، بينما ينفّذ المكوّن الداخلي العمل المتخصص!

جرّب بنفسك

-- main.lua
-- اجمع كل شيء معًا!

local Speaker = require('Speaker')
local MusicPlayer = require('MusicPlayer')

-- اقرأ المدخلات
local volume = tonumber(io.read())
local brand = io.read()
local trackName = io.read()

-- TODO: أنشئ Speaker بالحجم المعطى

-- TODO: أنشئ MusicPlayer مع brand و speaker

-- TODO: استدعِ method الـ play الخاصة بـ player مع track name

-- TODO: استدعِ method الـ stop الخاصة بـ player
quiz iconاختبر نفسك

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

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

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