تطبيق 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 الخاصة بك متميزة لتجنب أي سلوك غير متوقع.
التحدي
سهللنقم ببناء فئة 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، واعرض حالتها، واجعلها تهاجم الهدف، وتعالج نفسها، ثم اعرض حالتها مرة أخرى.
ستتلقى خمسة مدخلات:
- اسم الشخصية (سلسلة نصية)
- الصحة البدائية (رقم)
- قيمة الضرر (رقم)
- اسم الهدف المراد مهاجمته (سلسلة نصية)
- مقدار العلاج (رقم)
يجب أن يظهر مخرجك الشخصية وهي تستخدم كلتا قدرتي الـ 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: عرض حالة الشخصية مرة أخرى
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
4مشروع: بنك رقمي
إعداد المشروعطريقة الإيداع7تعدد الأشكال وإعادة التعريف
إعادة تعريف الدوالاستدعاء دوال الفئة الأبDuck Typingواجهة مشتركةالتحقق من النوعمراجعة - أدوار الموظفين2نمط النموذج الأولي للفئات
مفهوم النموذج الأوليالربط باستخدام __indexالمنشئ :new()تهيئة الخصائصنسخ مستقلةملخص - مصنع السيارات5تحميل المعاملات في OOP
جمع الكائناتطرح الكائناتدمج الكائناتمقارنة الكائنات (<, >)مراجعة - رياضيات المحفظة8التغليف
اصطلاحات التسميةاستخدام Closures للخصوصيةالوصول عبر Closuresجداول للقراءة فقطمنطق التحقق من الصحةمراجعة - الخزنة الآمنة11أنماط التصميم (مبسط)
دوال المصنعجدول Singletonنمط الـ Iteratorالمراقب (المستمع)مراجعة - مصنع الـ Logger3حالة الكائن وسلوكه
متغيرات النسخةدالات الجلب (Getter Methods)دالات التعيين (Setter Methods)الخصائص المحسوبةتنسيق النصوصالتحقق من المساواةمراجعة - درجة الطالب6أساسيات الوراثة
إعداد الوراثةوراثة الـ Methodsتوسيع الـ Constructorإضافة Methods للابنالمشترك مقابل الفريدملخص - التسلسل الهرمي للأشكال9التركيب و Mixins
علاقة "يحتوي على" (Has-A)التفويض (Delegation)Mixins بسيطةتطبيق Mixins متعددةMixins مقابل الوراثةملخص - تجميع الروبوت