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

الوصول عبر Closures

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

تكون متغيرات private local عديمة الفائدة إذا لم تتمكن من التفاعل معها مطلقًا. والحل هو Define getter وsetter methods inside the constructor، حيث يمكنها الوصول إلى نطاق closure.

بما أن هذه methods تُنشأ داخل :new()، فيمكنها الوصول إلى المتغيرات local. وتُسندها مباشرةً إلى الكائن:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- متغير خاص
    
    local obj = {}
    
    -- تعريف الدوال داخل المُنشئ
    function obj:getCount()
        return count
    end
    
    function obj:increment()
        count = count + 1
    end
    
    setmetatable(obj, Counter)
    return obj
end

يمكن الآن الوصول إلى المتغير الخاص count، ولكن فقط من خلال methods التي توفرها:

local c = Counter:new()
print(c:getCount())  -- 0
c:increment()
c:increment()
print(c:getCount())  -- 2
print(c.count)       -- nil (ما زال مخفياً!)

لاحظ أن :getCount() و:increment() مُعرَّفان على obj مباشرةً، وليس على جدول class. يحصل كل instance على نسخته الخاصة من هذه الدوال، مع وصول كل نسخة إلى count الخاص بها. هذه هي المفاضلة: تتطلب الخصوصية الحقيقية قدرًا أكبر قليلًا من الذاكرة، لأن methods لا تتم مشاركتها عبر النموذج الأولي.

challenge icon

التحدي

سهل

لنبنِ Temperature class تستخدم الخصوصية القائمة على closure لتخزين قيمة درجة الحرارة بوحدة Celsius، مع تعريف methods getter وsetter داخل constructor لتوفير وصول مُتحكَّم به!

ستنظّم كودك عبر ملفين:

  • Temperature.lua: أنشئ class تُخزَّن فيها قيمة درجة الحرارة في متغير local داخل constructor: مخفية تمامًا عن الوصول الخارجي. يجب أن يخزّن constructor :new(initialCelsius) درجة الحرارة في متغير local، ثم يعرّف هذه methods مباشرة على instance الكائن:
    • :getCelsius(): يعيد درجة الحرارة الحالية بوحدة Celsius
    • :setCelsius(value): يحدّث درجة الحرارة إلى قيمة جديدة
    • :getFahrenheit(): يعيد درجة الحرارة converted إلى Fahrenheit باستخدام Formula: (celsius * 9/5) + 32
  • main.lua: استخدم require لوحدة Temperature واقرأ قيمتين من input: درجة حرارة initial ودرجة حرارة جديدة لضبطها. أنشئ instance من Temperature باستخدام القيمة initial، واطبع قراءات Celsius وFahrenheit، ثم استخدم setter لتغيير درجة الحرارة واطبع القراءتين كلتيهما مرة أخرى.

ستتلقى inputين:

  1. درجة الحرارة initial بوحدة Celsius (رقم)
  2. درجة حرارة جديدة لضبطها (رقم)

يجب أن يتكون output الخاص بك من أربعة أسطر تعرض قراءات درجة الحرارة قبل change وبعدها:

Celsius: {initialValue}
Fahrenheit: {convertedInitial}
Celsius: {newValue}
Fahrenheit: {convertedNew}

على سبيل المثال، إذا كانت قيمتا input هما 0 و100، فيجب أن يكون output كما يلي:

Celsius: 0
Fahrenheit: 32
Celsius: 100
Fahrenheit: 212

تذكّر: يجب تخزين قيمة درجة الحرارة في متغير local داخل :new()، وليس على self. يتم تعريف methods getter وsetter داخل constructor، حيث يمكنها الوصول إلى هذا المتغير private من خلال closure. يجب أن تؤدي محاولة الوصول إلى temp.celsius أو temp._celsius مباشرةً إلى إرجاع nil!

جرّب بنفسك

-- استيراد وحدة Temperature
local Temperature = require('Temperature')

-- اقرأ قيم الإدخال
local initialTemp = tonumber(io.read())
local newTemp = tonumber(io.read())

-- TODO: أنشئ كائن Temperature بالقيمة الأولية

-- TODO: اطبع قراءات Celsius و Fahrenheit الأولية

-- TODO: استخدم الـ setter لتغيير درجة الحرارة إلى newTemp

-- TODO: اطبع قراءات Celsius و Fahrenheit المحدّثة
quiz iconاختبر نفسك

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

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

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