0Pricing
Lua Academy · درس

المنشئات وnew()

اكتب دوال منشئة تنشئ النسخ وتهيّئها

المنشئات وnew() درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.

مسؤولية المُنشئ

ينشئ المُنشئ نسخةً ويهيّئها. ويتلقى القيم الأولية، ويتحقق من صحتها، ويعيّن القيم الافتراضية للحقول المفقودة، ثم يعيد النسخة الجديدة. يضمن المُنشئ المصمم جيدًا أن تبدأ كل نسخة بحالة صالحة.

local Player = {}
Player.__index = Player

function Player.new(name, hp, mp)
  assert(type(name)=="string" and name~="","need name")
  return setmetatable({
    name = name,
    hp   = hp or 100,
    mp   = mp or 50,
    alive = true,
    items = {},
  }, Player)
end

local p = Player.new("Hero")
print(p.name, p.hp, p.mp)  -- Hero  100  50

المُنشئ الانسيابي

يعيد المُنشئ الانسيابي self من أساليب التعيين، مما يتيح تسلسل الأساليب أثناء الإنشاء. وهذا هو نمط الباني في Lua.

local Config = {}
Config.__index = Config

function Config.new()
  return setmetatable({_data={}}, Config)
end

function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end

local cfg = Config.new()
  :set("host","localhost")
  :set("port",8080)
  :set("debug",true)
  :build()

print(cfg.host, cfg.port)

مُنشئ النسخ

ينشئ مُنشئ النسخ نسخةً جديدة بالقيم نفسها الموجودة في نسخة أخرى. مهم: استخدم النسخ السطحي أو العميق بحسب ما إذا كان ينبغي مشاركة الجداول المتداخلة أو جعلها مستقلة.

local function deepCopy(orig)
  if type(orig)~="table" then return orig end
  local copy = {}
  for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
  return setmetatable(copy, getmetatable(orig))
end

local Item = {}
Item.__index = Item

function Item.new(name, stats)
  return setmetatable({name=name, stats=stats or {}}, Item)
end

function Item:clone()
  return deepCopy(self)
end

local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage)  -- 50 (unchanged)

المُنشئ مع التحقق

تحقق دائمًا من مدخلات المُنشئ. اطرح أخطاءً وصفية عند وجود مدخلات غير صالحة في المستوى 2 (مع تحميل المستدعي المسؤولية). يكتشف ذلك الأخطاء مبكرًا وينتج رسائل خطأ مفيدة.

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle.new(w, h)
  assert(type(w)=="number" and w>0,"width must be positive number")
  assert(type(h)=="number" and h>0,"height must be positive number")
  return setmetatable({width=w, height=h}, Rectangle)
end

function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end

local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter())  -- 15  16

نمط القيم الافتراضية

استخدم جدولًا للقيم الافتراضية لمعالجة معاملات المُنشئ الاختيارية بطريقة واضحة. ويجنبك ذلك سلاسل طويلة من x = x or default، ويجعل القيم الافتراضية صريحة وسهلة التغيير.

local Sprite = {}
Sprite.__index = Sprite

local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}

function Sprite.new(image, opts)
  local cfg = opts or {}
  local self = {image=image}
  for k,v in pairs(DEFAULTS) do
    self[k] = cfg[k] ~= nil and cfg[k] or v
  end
  return setmetatable(self, Sprite)
end

local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale)  -- 100 200 1

أساليب المصنع الساكنة

يمكن أن يحتوي الصنف على عدة أساليب مصنع لسيناريوهات إنشاء مختلفة. وهذا أوضح من تحميل مُنشئ واحد بعدد كبير من المعاملات الاختيارية.

local Color = {}
Color.__index = Color

function Color.fromRGB(r,g,b)
  return setmetatable({r=r,g=g,b=b}, Color)
end

function Color.fromHex(hex)
  hex = hex:gsub("#","")
  return setmetatable({
    r=tonumber(hex:sub(1,2),16),
    g=tonumber(hex:sub(3,4),16),
    b=tonumber(hex:sub(5,6),16),
  }, Color)
end

function Color:toHex()
  return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end

local red = Color.fromHex("#FF0000")
print(red:toHex())  -- #FF0000

سجل المُنشئات

استخدم سجلًا لتتبع جميع النسخ. يتيح ذلك إجراء عمليات عامة مثل "تدمير الكل" أو تكرار جميع الكائنات من نوع معين.

local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}

function Enemy.new(name, hp)
  local self = setmetatable({name=name, hp=hp}, Enemy)
  Enemy._all[#Enemy._all+1] = self
  return self
end

function Enemy.destroyAll()
  for _, e in ipairs(Enemy._all) do
    print("Destroying:", e.name)
  end
  Enemy._all = {}
end

Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all)  -- 2
Enemy.destroyAll()

التهيئة الكسولة

تكون بعض الحقول مكلفة حسابيًا. استخدم __index مع دالة لحسابها وتخزينها مؤقتًا عند أول وصول إليها.

local BigData = {}
BigData.__index = function(t, k)
  if k == "processed" then
    print("Computing processed...")
    local result = {}
    for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
    rawset(t,"processed",result)
    return result
  end
end

function BigData.new(raw)
  return setmetatable({raw=raw}, BigData)
end

local d = BigData.new({1,2,3,4,5})
print(d.processed[3])  -- Computing...  6
print(d.processed[3])  -- 6 (cached, no recompute)

النموذج الأولي من نسخة

استنسخ نسخةً لإنشاء نسخة أخرى بالقيم الأساسية نفسها. يحصل الاستنساخ على جدول البيانات الوصفية نفسه (أي الصنف نفسه) ونسخة من بيانات النسخة. وهذا مفيد لكائنات "القوالب".

local Unit = {}
Unit.__index = Unit

function Unit.new(t)
  return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end

function Unit:clone()
  return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end

function Unit:__tostring()
  return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end

local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))

أمان أخطاء المُنشئ

إذا فشل الإنشاء في منتصفه (مثلًا عند تخصيص مورد)، فتأكد من عدم خروج كائنات غير مكتملة. استخدم pcall لالتقاط أخطاء الإنشاء وتنظيف الموارد عند الحاجة.

local FileHandle = {}
FileHandle.__index = FileHandle

function FileHandle.new(path, mode)
  local f, err = io.open(path, mode or "r")
  if not f then
    return nil, "cannot open " .. path .. ": " .. err
  end
  return setmetatable({_f=f, path=path}, FileHandle)
end

function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end

local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
end

تحقق سريع

ما دور المُنشئ (new()) في البرمجة كائنية التوجه في Lua؟

مراجعة: المُنشئات

الملخص:

  • يتحقق المُنشئ من الصحة، ويهيّئ النسخة، ويستدعي setmetatable
  • استخدم جدول القيم الافتراضية لمعالجة المعاملات الاختيارية بوضوح
  • استخدم عدة أساليب مصنع لسيناريوهات الإنشاء المختلفة
  • استخدم مُنشئ النسخ لكائنات القوالب
  • استخدم التهيئة الكسولة عبر __index للحقول المكلفة حسابيًا
  • أعد nil+err من المُنشئ عند الفشل (مثل فشل تخصيص الموارد)

الأسئلة الشائعة

هل درس «المنشئات وnew()» مجاني؟

نعم — نص درس «المنشئات وnew()» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.

ماذا ستتعلم في «المنشئات وnew()»؟

اكتب دوال منشئة تنشئ النسخ وتهيّئها تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟

لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «المنشئات وnew()»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟

نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الفئات عبر جداول البيانات الوصفية
  2. المنشئات وnew()
  3. أساليب النسخ وself
  4. التغليف باستخدام الإغلاقات
← العودة إلى Lua Academy