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

علاقة "يحتوي على" (Has-A)

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

خلال هذه الدورة، استخدمتَ الوراثة لمشاركة السلوك بين الأصناف — فـ Dog "هو" Animal. لكن الوراثة ليست دائمًا الأداة الصحيحة.

في بعض الأحيان، لا تشترك الكائنات في شجرة عائلة؛ بدلاً من ذلك، ببساطة يحتوي كائن واحد على كائن آخر. يُسمى هذا التركيب (composition)، وهو يمثل علاقة "لديه-واحد" (has-a).

فكر في سيارة. السيارة ليست نوعاً من المحركات—بل هي تمتلك محركاً. المحرك هو كائن منفصل موجود داخل السيارة:

local Engine = {}
Engine.__index = Engine

function Engine:new(horsepower)
    local obj = {horsepower = horsepower}
    setmetatable(obj, Engine)
    return obj
end

local Car = {}
Car.__index = Car

function Car:new(model, engine)
    local obj = {
        model = model,
        engine = engine  -- تخزين كائن Engine داخل Car
    }
    setmetatable(obj, Car)
    return obj
end

عند إنشاء سيارة، تقوم بتمرير كائن محرك (engine object) موجود إلى المنشئ (constructor) الخاص بها:

local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)

print(myCar.engine.horsepower)  -- 200

لا ترث السيارة من المحرك—بل تحتفظ ببساطة بمرجع له. وهذا يحافظ على استقلالية كلا الـ classes. يمكنك استبداله بمحرك مختلف، أو استخدام نفس الـ engine class في دراجة نارية.

يمنحك التركيب (Composition) مرونة لا تستطيع الوراثة (inheritance) توفيرها: فأنت تقوم بتجميع الكائنات من أجزاء بدلاً من حصرها في تسلسل هرمي عائلي صارم.

challenge icon

التحدي

سهل

لنقم ببناء نظام كمبيوتر باستخدام التركيب (composition)! بدلاً من الوراثة، ستقوم بإنشاء Computer يحتوي على CPU بداخله—مما يوضح علاقة "has-a".

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

  • CPU.lua: قم بإنشاء فئة CPU مع منشئ :new(brand, speed) يقوم بتخزين اسم العلامة التجارية والسرعة بوحدة GHz. قم بتضمين طريقة :getInfo() التي تعيد سلسلة نصية بالتنسيق التالي: {brand} @ {speed}GHz
  • Computer.lua: قم بإنشاء فئة Computer يقبل منشئها :new(model, cpu) اسم الطراز وكائن CPU. يقوم الـ Computer بتخزين كائن CPU بداخله (التركيب!). قم بتضمين طريقة :describe() التي تطبع طراز الكمبيوتر ومعلومات المعالج الخاص به.
  • main.lua: اجمع كل شيء معاً! اقرأ المدخلات لعلامة المعالج التجارية، وسرعة المعالج، وطراز الكمبيوتر. قم بإنشاء كائن CPU أولاً، ثم مرره إلى منشئ Computer. أخيراً، استدعِ طريقة :describe() الخاصة بالكمبيوتر.

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

  1. علامة المعالج التجارية (سلسلة نصية)
  2. سرعة المعالج بوحدة GHz (رقم)
  3. اسم طراز الكمبيوتر (سلسلة نصية)

يجب أن يظهر مخرجك وصف الكمبيوتر، والذي يتضمن معلومات من المعالج المحتوى بداخله:

Model: {model}
CPU: {brand} @ {speed}GHz

على سبيل المثال، إذا كانت المدخلات هي Intel و 3.5 و WorkStation، فيجب أن يكون المخرج:

Model: WorkStation
CPU: Intel @ 3.5GHz

لاحظ كيف أن Computer لا يرث من CPU—بل يحتفظ ببساطة بمرجع إليه. تصل طريقة :describe() الخاصة بالـ Computer إلى بيانات CPU من خلال الكائن المخزن، مما يوضح كيف يتيح لك التركيب بناء كائنات معقدة من أجزاء أبسط!

ورقة مرجعية

يمكن للكائنات أن ترتبط من خلال التركيب (composition)، والذي يمثل علاقة "يحتوي على" (has-a). بدلاً من الوراثة، يحتوي كائن واحد على كائن آخر كمكون.

مثال على التركيب مع سيارة تحتوي على محرك:

local Engine = {}
Engine.__index = Engine

function Engine:new(horsepower)
    local obj = {horsepower = horsepower}
    setmetatable(obj, Engine)
    return obj
end

local Car = {}
Car.__index = Car

function Car:new(model, engine)
    local obj = {
        model = model,
        engine = engine  -- تخزين كائن المحرك داخل السيارة
    }
    setmetatable(obj, Car)
    return obj
end

إنشاء واستخدام الكائنات المركبة:

local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)

print(myCar.engine.horsepower)  -- 200

يوفر التركيب مرونة من خلال تجميع الكائنات من أجزاء بدلاً من استخدام تسلسلات هرمية جامدة للوراثة. تظل المكونات مستقلة ويمكن إعادة استخدامها عبر فئات مختلفة.

جرّب بنفسك

-- main.lua
-- تجميع كل شيء معاً باستخدام التركيب (composition)

local CPU = require('CPU')
local Computer = require('Computer')

-- قراءة المدخلات
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()

-- TODO: إنشاء كائن CPU مع العلامة التجارية والسرعة

-- TODO: إنشاء كائن Computer مع الطراز وكائن CPU

-- TODO: استدعاء طريقة describe() الخاصة بالكمبيوتر لطباعة المخرجات
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming