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

Duck Typing

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

لا تهتم Lua بـ class الكائن. إنها تهتم فقط بما يستطيع الكائن فعله. يُسمّى هذا المفهوم duck typing: "إذا كان يمشي مثل duck ويصدر صوتًا مثل duck، فهو duck." وبمصطلحات البرمجة، إذا كان لدى الكائن الـ method الذي تستدعيه، فسيعمل.

هذا يعني أنه يمكن استخدام فئات غير مرتبطة تمامًا معًا، ما دامت تشترك في اسم الأسلوب نفسه:

local Circle = {}
Circle.__index = Circle
function Circle:new() 
    local obj = {}
    setmetatable(obj, Circle)
    return obj
end
function Circle:draw()
    print("Drawing a circle")
end

local Square = {}
Square.__index = Square
function Square:new()
    local obj = {}
    setmetatable(obj, Square)
    return obj
end
function Square:draw()
    print("Drawing a square")
end

لا تربط هذه الأصناف علاقةُ توريث؛ فهي مستقلة تمامًا. ومع ذلك، يمكننا التعامل معها بالطريقة نفسها:

local shapes = {Circle:new(), Square:new(), Circle:new()}

for _, shape in ipairs(shapes) do
    shape:draw()
end
-- المخرجات:
-- رسم دائرة
-- رسم مربع
-- رسم دائرة

لا تتحقق الحلقة من نوع كل كائن. بل تستدعي ببساطة :draw() وتفترض وجود هذه الطريقة. هذه المرونة قوية. يمكنك إضافة أنواع جديدة من الأشكال من دون تعديل رمز الحلقة على الإطلاق. ما دام الصنف الجديد يطبّق :draw()، فسيعمل ببساطة.

challenge icon

التحدي

سهل

لنوضّح قوة duck typing من خلال بناء نظام notification باستخدام classes غير مترابطة تمامًا، ويمكن معالجة all منها بالطريقة نفسها!

ستنشئ ثلاث classes مستقلة للـ notification، ولا يرث أيّ منها من الآخر، لكنها all تنفّذ method :send(). وهذا يعني أنه يمكنك التكرار عبر مجموعة مختلطة واستدعاء :send() على كل one منها دون الاهتمام بنوعه الفعلي.

ستنظّم كودك عبر four files:

  • Email.lua: class تحتوي على Constructor :new(recipient) يخزّن الجهة التي يُرسَل إليها البريد الإلكتروني. ويجب أن تطبع method :send() الخاصة بها Emailing {recipient}.
  • SMS.lua: class منفصلة تمامًا تحتوي على Constructor :new(phoneNumber). ويجب أن تطبع method :send() الخاصة بها Texting {phoneNumber}.
  • PushNotification.lua: class مستقلة أخرى تحتوي على Constructor :new(deviceId). ويجب أن تطبع method :send() الخاصة بها Pushing to {deviceId}.
  • main.lua: اجمع كل شيء معًا! اقرأ three inputs، وأنشئ instance واحدة من كل نوع من أنواع notification، وضعها all في table واحدة، ثم Loop عبرها واستدعِ :send() على كل one منها.

ستتلقى three inputs:

  1. مستلم بريد إلكتروني (مثلًا، alice@example.com)
  2. رقم هاتف (مثلًا، 555-1234)
  3. معرّف device (مثلًا، device_99)

في ملفك الرئيسي، أنشئ كائنات notification الثلاثة، وخزّنها في table، وكرّر عبر table مستدعيًا :send() على كل one منها. يجب أن يكون الترتيب: Email أولًا، ثم SMS، ثم PushNotification.

على سبيل المثال، إذا كانت inputs هي bob@mail.com و555-9876 وphone_42، فيجب أن يكون Output:

Emailing bob@mail.com
Texting 555-9876
Pushing to phone_42

لاحظ أن Loop الخاص بك لا يحتاج إلى التحقّق من نوع كل كائن. إنه يثق فقط بأن كل كائن في المجموعة لديه method :send(). هذه هي duck typing أثناء العمل! إذا كان يستطيع :send()، فهو notification.

جرّب بنفسك

-- main.lua
-- اجمع جميع أنواع الإشعارات معًا وأظهر duck typing

-- استيراد فئات الإشعارات
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')

-- قراءة المدخلات
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()

-- TODO: أنشئ مثيلاً واحدًا من كل نوع إشعار

-- TODO: ضع جميع الإشعارات في جدول واحد (Email أولاً، ثم SMS، ثم PushNotification)

-- TODO: مر عبر الجدول واستدعِ :send() على كل إشعار
-- هذا يوضح duck typing - لا نتحقق من النوع، بل نستدعي فقط :send()
quiz iconاختبر نفسك

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

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

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