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

التفويض (Delegation)

جزء من قسم Object Oriented Programming في رحلة Lua على Coddy — الدرس 50 من 70.

تخزين كائن داخل كائن آخر هو مجرد الخطوة الأولى. تكمن القوة الحقيقية للتركيب (composition) في التفويض (delegation)—عندما يقوم الكائن الخارجي بتمرير استدعاءات الميثود (method calls) إلى مكوناته الداخلية.

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

في الكود، يعني هذا أن فئة Car توفر طريقة :start() بسيطة تُفوض العمل الفعلي للمحرك:

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) الخاصة بك. فهم يتفاعلون مع السيارة، وليس مع أجزائها الداخلية. إذا قمت لاحقاً بتبديل تنفيذ المحرك بآخر مختلف، فستظل الواجهة العامة للسيارة كما هي، ولن يتغير سوى التفويض الداخلي.

challenge icon

التحدي

سهل

لنقم ببناء نظام مشغل موسيقى يوضح مفهوم التفويض (Delegation)! ستقوم بإنشاء مكون Speaker و MusicPlayer يحتويه. لن يقوم المشغل بمعالجة إخراج الصوت مباشرة - بدلاً من ذلك، سيفوض هذه المسؤولية لمكبر الصوت الداخلي الخاص به.

ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:

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

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

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

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

{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 لا يعرف كيفية إنتاج الصوت - فهو ببساطة يخبر مكبر الصوت الخاص به بمعالجة هذا الجزء. هذا هو التفويض في أبهى صوره: الكائن الخارجي يوفر واجهة نظيفة بينما يقوم المكون الداخلي بالعمل المتخصص!

ورقة مرجعية

يسمح التفويض (Delegation) للكائن الخارجي بتوجيه استدعاءات الدوال إلى مكوناته الداخلية، مما يحافظ على فصل المسؤوليات وإنشاء واجهات برمجية نظيفة.

يوفر الكائن الخارجي دوالاً بسيطة تفوض العمل إلى الكائنات الداخلية:

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

يتعامل الكائن الداخلي مع منطقه الخاص والمتخصص:

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

local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- المخرجات:
-- Turning the key...
-- Engine running at 250 HP

فوائد التفويض:

  • لا تحتاج الفئة الخارجية إلى معرفة كيفية عمل الكائن الداخلي
  • يتفاعل المستخدمون مع واجهة عامة نظيفة
  • يمكن تبديل التنفيذات الداخلية دون تغيير الواجهة العامة

جرّب بنفسك

-- 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 بمستوى الصوت volume المعطى

-- TODO: قم بإنشاء MusicPlayer باستخدام brand و speaker

-- TODO: استدعِ طريقة play الخاصة بالمشغل مع اسم المسار

-- TODO: استدعِ طريقة stop الخاصة بالمشغل
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming