January 29, 2026 (7mo ago) — last updated June 23, 2026 (3mo ago)

الفئات مقابل البنى: دليل أداء للمطورين

تعرف على الفرق بين الفئات والبنى ومتى تختار كل منهما لتحسين الأداء وتقليل تخصيصات الذاكرة وجمع القمامة في C#, Swift وC++.

← Back to blog
Cover Image for الفئات مقابل البنى: دليل أداء للمطورين

الفارق الأساسي واضح وحاسم: الفئات هي أنواع مرجعية والبنى هي أنواع قيمة. هذا التمييز يؤثر مباشرةً على الذاكرة، سلوك النسخ، ومحلية الكاش. فهم متى تختار كل منهما يساعدك على كتابة كود أنظف وأكثر كفاءة عبر C# وSwift وC++.

الفئات مقابل البنى: دليل أداء للمطورين

الملخص: اكتشف الفرق بين الفئات والبنى، ومتى تختار كل منهما لتحسين الأداء وتقليل تخصيص الذاكرة وجمع القمامة في C# وSwift وC++.

المقدمة

الفارق الأساسي واضح وحاسم: الفئات هي أنواع مرجعية والبنى هي أنواع قيمة1. هذا الفارق يؤثر مباشرة في تخطيط الذاكرة، وسلوك النسخ، ومحلية الكاش، وأداء وقت التشغيل. فهم القواعد العامة لكل لغة واستخدام الأنماط الصحيحة يساعدك على كتابة كود نظيف وأسرع مع سلوك متوقع.

الفرق الأساسي باختصار

  • الفئات تخزن الكائنات على الكومة؛ المتغير يحمل مرجعًا لذلك الكائن. نسخ المرجع لا ينسخ الكائن نفسه، ولذلك عدة مراجع يمكن أن تشير إلى نفس المثيل1.
  • البنى تمثل قيمة ملموسة تُنسخ بالكامل عند الإسناد، وتُخزن عادةً على المكدس أو مضمنة داخل الحاويات، لذلك التعديل في نسخة لا يؤثر على الأصل1.

هذا التمييز يحدد متى تختار هوية (class) أو قيمة (struct) ويؤثر على محلية الذاكرة ومحمل جمع القمامة لاحقًا.

مخطط يوضح تخزين البنى على المكدس ومرجعية الفئات من المكدس إلى الكومة.

مقارنة سريعة: أنواع مرجعية مقابل أنواع قيمة

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

استخدم فئة عندما تحتاج هوية مشتركة. استخدم بنية عندما تحتاج قيمة بسيطة ومستقلة يمكن نسخها دون آثار جانبية.

هذه المبادئ توجّه المقايضات الأعمق للأداء مثل تخصيص الكومة مقابل المكدس، محلية الكاش، وضغط جمع القمامة.

تأثير تخصيص الذاكرة على الأداء

تخطيط الذاكرة يؤثر على الكمون والإنتاجية. الوصول إلى كائن عبر مرجع يتطلب متابعة المؤشر للوصول إلى بيانات على الكومة، وهو ما يضيف تكلفة زمنية ومشكلات محلية الكاش. البنى المخزنة متتالياً—مثل مصفوفات البنى—تحسّن نجاحات الكاش وتسرّع الحلقات الضيقة مقارنةً بتخصيصات منفصلة لكل مثيل فئة56.

تكاليف جمع القمامة

الكائنات على الكومة تُخضع النظام لنشاط جمع القمامة. التخصيص المتكرر لكائنات قصيرة العمر يزيد ضغط جمع القمامة وقد يسبب توقفات قصيرة في التنفيذ، ما يؤثر على الكمون في الأنظمة الحساسة للأداء3. استخدام أنواع القيمة للعديد من الكائنات الصغيرة يقلل من نشاط جمع القمامة ويحسّن استقرار زمن الاستجابة.

التخصيص على الكومة يمكن أن يضيف تكلفة غير مباشرة عبر نشاط جمع القمامة؛ البنى تقلل هذا العبء عندما تُستخدم بشكل مناسب.

محلية الكاش والإنتاجية

وحدات المعالجة تعتمد بشكل كبير على الكاش. التخطيط المتجاور للبيانات (contiguous layouts) يحسّن نجاحات الكاش. ترتيب البيانات على الكومة عبر تخصيصات متناثرة يزيد فقدان الكاش ويقلّل الإنتاجية؛ لذلك في أنابيب معالجة البيانات والحلقات الضيقة، تكوينات القيمة المتجاورة تعطي ميزة أداء محسوسة56.

فخ التغليف (Boxing)

التغليف يحدث عندما يُحوّل نوع قيمة إلى نوع مرجعي، مثل عند وضعه في مجموعة تتوقع كائنات. التغليف يخلق كائنًا على الكومة وينسخ القيمة إليه، مما يُفقد مزايا الأداء المرتبطة بالبنى ويزيد عبء جمع القمامة—لذلك تجنّب التغليف عند السعي لأداء أعلى4.

سلوكيات حسب اللغة: C#, C++, وSwift

اللغات تفرض أو تشجع أنماطًا مختلفة؛ معرفة قواعد كل لغة ضرورية لاتخاذ قرار صحيح.

مخطط يقارن خصائص لغات البرمجة C# وC++ وSwift، مع التركيز على الأنواع المرجعية مقابل القيمة ومرونة الكائنات.

C# — فصل واضح بين القيمة والمرجع

في C# الفئة = نوع مرجعي والبنية = نوع قيمة. استخدم الفئات للكيانات ذات الهوية (مثل Customer أو DatabaseConnection) والبنى للقيم الصغيرة وغير القابلة للتغيير (مثل Point أو Color). اجعل البنى صغيرة وغير قابلة للتغيير لتجنب أخطاء الدلالات وتكاليف النسخ المفاجئة1.

C++ — مرونة أكبر مع أعراف تصميم

في C++ الفرق النحوي الوحيد بين struct وclass هو الوصول الافتراضي؛ يمكن تخصيصهما على المكدس أو الكومة، ولهما دوال ووراثة. العُرف هو استخدام struct لمجموعات البيانات البسيطة وclass للكيانات المغلّفة وإدارة الموارد عبر RAII. هذه المرونة تتطلب قرارات تصميمية واعية بدلًا من قواعد لغوية صارمة5.

Swift — توجّه قوي نحو القيمة

تشجع Swift استخدام البنى في معظم الحالات. البنى في Swift تدعم الدوال، الامتدادات، والالتزام بالبرتوكولات، ما يجعلها خيارًا قويًا وآمنًا افتراضيًا. اختر الفئات فقط عندما تكون الدلالات المرجعية أو الهوية أو التوافق مع Objective‑C مطلوبة2.

متى تختار بنية لأقصى كفاءة

البنى مناسبة لحزم بيانات صغيرة وغير قابلة للتغيير تُعرّف هويتها بالكامل بقِيَمها. أمثلة:

  • بيانات هندسية: Point2D أو RGBColor
  • قيم مالية صغيرة: Money (المبلغ + العملة)
  • DTOs صغيرة في أنابيب بيانات عالية الإنتاجية

قاعدة عملية شائعة هي أن تجعل البنية صغيرة (تقريبًا 16–32 بايت)؛ إذا أصبحت أكبر، قد تصبح تكلفة النسخ أعلى من تمرير مرجع5.

قواعد عملية

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

هذه قواعد تقلل أخطاء الدلالات وفخاخ الأداء مثل النسخ الزائد والتغليف.

دليل لاختيار البنى للبيانات الصغيرة من نوع القيمة مثل RGB، نقطة ثنائية الأبعاد، والنقود، مع إرشاد 16 بايت.

أخطار شائعة وإعادة صياغة

مشكلتان شائعتان هما البنى القابلة للتغيير والتغليف المفرط.

  • البنى القابلة للتغيير قد تخلق سلوكًا مفاجئًا لأن التعديلات تؤثر على نسخة فقط. أعد صياغة البنى القابلة للتغيير إلى بنى غير قابلة للتغيير تُرجع مثيلات جديدة.
  • التغليف قد يحدث ضمنيًا في واجهات برمجة التطبيقات والمجموعات؛ حدد مواضع التغليف وأزلها للحفاظ على مزايا البنى.

مثال (C#): من بنية قابلة للتغيير إلى بنية غير قابلة للتغيير

// PITFALL: Mutable struct public struct MutablePoint { public int X { get; set; } public int Y { get; set; }

public void Move(int dx, int dy)
{
    X += dx;
    Y += dy;
}

}

// REFACTOR: Immutable struct public readonly struct ImmutablePoint { public int X { get; } public int Y { get; }

public ImmutablePoint(int x, int y)
{
    X = x;
    Y = y;
}

public ImmutablePoint MovedBy(int dx, int dy)
{
    return new ImmutablePoint(X + dx, Y + dy);
}

}

هذه الصياغة توضح النية وتمنع الفساد العرضي للحالة. لممارسات كتابة شيفرة نظيفة أكثر، انظر دليل مبادئنا: https://cleancodeguy.com/blog/clean-coding-principles.

أسئلة شائعة قصيرة

س1: متى أستخدم بنية بدل فئة؟

استخدم بنية عندما يكون النوع صغيرًا وغير قابل للتغيير ويمثل قيمة بدلًا من هوية، مثل النقاط والألوان وDTOs الصغيرة.

س2: ما الأخطاء التي تضر بالأداء؟

تجنب البنى الكبيرة أو القابلة للتغيير، وتجنّب التغليف إلى كائنات على الكومة لأن ذلك يلغي فوائد الأداء لأنواع القيمة4.

س3: كيف أتابع قراراتي حسب اللغة؟

اتبع أعراف اللغة: C# يميّز النوع المرجعي عن القيمة؛ C++ يعتمد على أعراف التصميم؛ Swift يفضّل القيمة افتراضيًا. تعلّم قواعد المنصة قبل تطبيق الأنماط عبر لغات12.


في Clean Code Guy نساعد الفرق على تطبيق هذه المبادئ على قواعد الشيفرة الحقيقية. عمليات تنظيف قواعد الشيفرة وإعادة التأهيل الجاهزة للذكاء الاصطناعي تجعل البرامج أسرع وأكثر أمانًا وأسهل في الصيانة. زر https://cleancode.com لمعرفة المزيد.

1.
2.
Apple Developer Documentation, “Structures and Classes,” https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
5.
NDepend blog, “Class vs Struct in C#: Making Informed Choices,” https://blog.ndepend.com/class-vs-struct-in-c-making-informed-choices/
← Back to blog
🙋🏻‍♂️

الذكاء الاصطناعي يكتب الكود.
أنت تجعله يدوم.

في عصر تسريع الذكاء الاصطناعي، الكود النظيف ليس مجرد ممارسة جيدة — إنه الفرق بين الأنظمة التي تتوسع وقواعد الكود التي تنهار تحت وزنها.