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

تطبيق Mixins متعددة

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

تضيف الـ mixin الواحدة مجموعة واحدة من السلوكيات إلى الفئة (class). لكن الكائنات الحقيقية غالباً ما تحتاج إلى قدرات من مصادر متعددة. قد يحتاج كائن اللعبة إلى التحرك و أن يكون مرئياً على الشاشة—وهما أمران منفصلان لا ينتميان إلى نفس الـ mixin.

الحل بسيط: قم بتطبيق عدة mixins على نفس الـ class. كل mixin يساهم بالـ methods الخاصة به، وينتهي الأمر بالـ class بامتلاكها جميعاً:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

قم بتطبيق كلا الـ mixins على الفئة (class) الخاصة بك باستخدام نفس الدالة المساعدة من قبل:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

الآن، يمكن لمثيلات GameObject التحرك وعرض نفسها:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- يظهر في 5، 3

تنبيه: إذا قام اثنان من الـ mixins بتعريف نفس اسم الـ method، فإن الثاني الذي يتم تطبيقه سيحل محل الأول. حافظ على دوال الـ mixin الخاصة بك متميزة لتجنب أي سلوك غير متوقع.

challenge icon

التحدي

سهل

لنقم ببناء فئة Character للعبة تجمع بين قدرات متعددة باستخدام الـ mixins! ستكون شخصيتك قادرة على مهاجمة الأعداء وعلاج نفسها في نفس الوقت — وهما سلوكان متميزان يأتيان من mixins منفصلة.

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

  • Attacker.lua: قم بإنشاء mixin يحتوي على طريقة :attack(targetName) تطبع {self.name} attacks {targetName} for {self.damage} damage! (يفترض أن الكائن يحتوي على حقول name و damage)
  • Healer.lua: قم بإنشاء mixin يحتوي على طريقة :heal(amount) تضيف القيمة إلى self.health وتطبع {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: قم بإنشاء فئة Character مع منشئ :new(name, health, damage) يقوم بتخزين السمات الثلاث. قم بتطبيق كل من mixins الـ Attacker و Healer بحيث يمكن لكل شخصية الهجوم والعلاج. قم بتضمين طريقة :status() تطبع {name} - Health: {health}, Damage: {damage}
  • main.lua: اكتب الدالة المساعدة applyMixin هنا. اقرأ المدخلات لاسم الشخصية، وصحتها، وقيمة الضرر، والهدف المراد مهاجمته، ومقدار العلاج. أنشئ Character، واعرض حالتها، واجعلها تهاجم الهدف، وتعالج نفسها، ثم اعرض حالتها مرة أخرى.

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

  1. اسم الشخصية (سلسلة نصية)
  2. الصحة البدائية (رقم)
  3. قيمة الضرر (رقم)
  4. اسم الهدف المراد مهاجمته (سلسلة نصية)
  5. مقدار العلاج (رقم)

يجب أن يظهر مخرجك الشخصية وهي تستخدم كلتا قدرتي الـ mixin:

{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}

على سبيل المثال، إذا كانت المدخلات هي Warrior، و 100، و 25، و Goblin، و 30، فيجب أن يكون المخرج:

Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25

يساهم كل mixin بطريقته الخاصة في فئة Character. لا ترث الشخصية من أي من الـ mixin — بل تكتسب قدراتهما ببساطة من خلال دالة applyMixin. هذه هي قوة الجمع بين عدة mixins!

ورقة مرجعية

يمكن تطبيق عدة mixins على فئة (class) واحدة لدمج مجموعات مختلفة من السلوكيات. يساهم كل mixin بطرقه (methods) الخاصة في الفئة.

قم بتعريف mixins منفصلة لاهتمامات مختلفة:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

قم بتطبيق عدة mixins على فئة باستخدام الدالة المساعدة applyMixin:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

تمتلك الفئة الآن طرقاً (methods) من جميع الـ mixins المطبقة:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- Showing at 5, 3

هام: إذا قام اثنان من الـ mixins بتعريف نفس اسم الطريقة (method name)، فإن الـ mixin الثاني المطبق سيحل محل الأول. حافظ على تميز أسماء الطرق عبر الـ mixins لتجنب التعارضات.

جرّب بنفسك

-- الملف الرئيسي

-- TODO: اكتب الدالة المساعدة applyMixin
-- يجب أن تقوم هذه الدالة بنسخ جميع الأساليب (methods) من جدول mixin إلى الجدول المستهدف (target)
local function applyMixin(target, mixin)
    -- TODO: تنفيذ تطبيق الـ mixin
end

-- اجعل applyMixin متاحاً بشكل عام حتى يتمكن Character.lua من استخدامه
_G.applyMixin = applyMixin

local Character = require('Character')

-- قراءة المدخلات
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())

-- TODO: إنشاء شخصية (Character) بالاسم، الصحة، والضرر المعطى

-- TODO: عرض حالة الشخصية

-- TODO: اجعل الشخصية تهاجم الهدف

-- TODO: اجعل الشخصية تعالج نفسها

-- TODO: عرض حالة الشخصية مرة أخرى
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming