تطبيق Mixins متعددة
جزء من قسم البرمجة كائنية التوجه في رحلة Lua على Coddy. الدرس 52 من 70.
يضيف mixin واحد مجموعةً واحدةً من السلوكيات إلى class. لكن الكائنات الحقيقية غالبًا ما تحتاج إلى إمكانات من مصادر متعددة. قد يحتاج كائن اللعبة إلى التحرك و الظهور على الشاشة: وهما جانبان منفصلان لا ينتميان إلى mixin نفسه.
الحل مباشر: استخدم apply لعدة 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طبّق كلا من mixin على صفّك باستخدام دالة المساعدة نفسها من قبل:
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تنبيه واحد: إذا كان لدى اثنين من mixin تعريف لـ method بالاسم نفسه، فسيكتب الثاني الذي تم تطبيقه فوق الأول. احرص على أن تكون methods الخاصة بـ mixin متميزة لتجنب السلوك غير المتوقع.
التحدي
سهللنبنِ class باسم Character للعبة تجمع بين إمكانات متعددة باستخدام mixins! سيتمكن character من مهاجمة الأعداء ومعالجة نفسه: سلوكان متميزان يأتيان من mixins منفصلين.
ستنظم كودك عبر أربعة ملفات:
Attacker.lua: أنشئ mixin يحتوي على method باسم:attack(targetName)يطبع{self.name} attacks {targetName} for {self.damage} damage!(يفترض أن الكائن has حقليnameوdamage)Healer.lua: أنشئ mixin يحتوي على method باسم:heal(amount)يضيف amount إلىself.healthويطبع{self.name} heals for {amount}. Health: {newHealth}Character.lua: أنشئ class باسم Character مع constructor هو:new(name, health, damage)يخزن السمات الثلاث كلها. طبّق كلاً من mixinَي Attacker وHealer حتى يتمكن كل character من الهجوم والمعالجة. أدرج method باسم:status()يطبع{name} - Health: {health}, Damage: {damage}main.lua: اكتب helper function المسماةapplyMixinهنا. اقرأ inputs لاسم character وhealth وdamage وهدف للهجوم وamount للمعالجة. أنشئ Character، واعرض حالته، واجعله يهاجم الهدف، ثم يعالج نفسه، وبعد ذلك اعرض حالته مرة أخرى.
ستتلقى خمسة inputs:
- اسم Character (سلسلة نصية)
- health الابتدائي (رقم)
- قيمة damage (رقم)
- اسم الهدف المراد مهاجمته (سلسلة نصية)
- amount المراد معالجته (رقم)
يجب أن يُظهر إخراجك character وهو يستخدم قدرات كلا mixinين:
{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}على سبيل المثال، إذا كانت inputs هي 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 بـ method خاص به في class Character. لا يرث character من أيٍّ من mixinين. بل يكتسب قدراتهما ببساطة من خلال function applyMixin. هذه هي قوة الجمع بين 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 بالاسم وhealth وdamage المعطاة
-- TODO: اعرض حالة الشخصية
-- TODO: اجعل الشخصية تهاجم الهدف
-- TODO: اجعل الشخصية تشفي نفسها
-- TODO: اعرض حالة الشخصية مرة أخرى
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 مقابل الوراثةملخص - تجميع الروبوتتدرّب بنفسك: مترجم Lua عبر الإنترنت