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

الخصائص من أجل التغليف

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

تعد الخصائص (Properties) الأداة الأساسية لتنفيذ التغليف (encapsulation) في لغة C#. فبدلاً من كشف الحقول (fields) مباشرة، تقوم بتغليفها بخصائص تتحكم في كيفية الوصول إلى البيانات وتعديلها.

يجمع هذا النمط بين حقل خاص وخاصية عامة تتضمن التحقق من الصحة أو منطقاً معيناً في أدوات الوصول (accessors) الخاصة بها:

public class Temperature
{
    private double celsius;
    
    public double Celsius
    {
        get { return celsius; }
        set
        {
            if (value < -273.15)
                celsius = -273.15;  // الحد الأدنى للصفر المطلق
            else
                celsius = value;
        }
    }
}

الآن لا يمكن للكود الخارجي تعيين درجة حرارة مستحيلة. تعمل الخاصية كحارس بوابة، مما يضمن بقاء الكائن الخاص بك دائماً في حالة صالحة. هذا هو مفهوم التغليف (encapsulation) قيد التنفيذ - حيث تكون البيانات الداخلية محمية مع بقائها قابلة للوصول من خلال واجهة محكومة.

يمكنك أيضاً استخدام الخصائص لحساب القيم أو إحداث تأثيرات جانبية:

public double Fahrenheit
{
    get { return celsius * 9 / 5 + 32; }
    set { celsius = (value - 32) * 5 / 9; }
}

يرى العالم الخارجي خاصيتين، ولكن داخلياً يوجد حقل واحد فقط. تتيح لك الخصائص تغيير تفاصيل التنفيذ دون كسر الكود الذي يستخدم فئتك (class) - وهي ميزة رئيسية للتغليف (encapsulation) السليم.

challenge icon

التحدي

سهل

لنقم ببناء نظام مخزون منتجات يستخدم الخصائص (properties) لحماية سلامة البيانات. ستقوم بإنشاء فئة (class) حيث لا يمكن للأسعار أن تكون سالبة أبداً، ويتم الاحتفاظ بالكميات دائماً ضمن حدود صالحة - مما يوضح كيف تعمل الخصائص كحراس لبياناتك.

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

  • Product.cs: أنشئ فئة Product داخل مساحة الأسماء Inventory التي تدير معلومات المنتج مع التحقق من الصحة من خلال الخصائص. يحتاج منتجك إلى:
    • حقل خاص price (decimal) مع خاصية عامة Price تضمن عدم انخفاض السعر أبداً عن 0 - إذا حاول شخص ما تعيين سعر سالب، فيجب تخزينه كـ 0 بدلاً من ذلك
    • حقل خاص quantity (int) مع خاصية عامة Quantity تبقي القيم بين 0 و 1000 - القيم الأقل من 0 تصبح 0، والقيم الأعلى من 1000 تصبح 1000
    • خاصية عامة تلقائية التنفيذ (auto-implemented property) باسم Name (string)
    • خاصية محسوبة للقراءة فقط TotalValue تعيد Price * Quantity
    قم بتضمين منشئ (constructor) يقبل الاسم، السعر، والكمية (بهذا الترتيب) ويقوم بتعيين جميع القيم من خلال الخصائص بحيث يتم تطبيق التحقق من الصحة.
  • Program.cs: في ملفك الرئيسي، أنشئ Product باستخدام قيم الإدخال. ثم حاول تعديل السعر والكمية بقيم إدخال إضافية قد تكون غير صالحة. اطبع حالة المنتج بعد الإنشاء وبعد كل تعديل لترى كيف تحمي الخصائص البيانات.

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

  • اسم المنتج
  • السعر الأولي (decimal)
  • الكمية الأولية (integer)
  • السعر الجديد المراد تعيينه (decimal، قد يكون سالباً)
  • الكمية الجديدة المراد تعيينها (integer، قد تكون خارج النطاق)

اطبع المخرجات بهذا التنسيق:

After creation:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
After modifications:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}

على سبيل المثال، إذا كانت المدخلات هي Laptop، و 999.99، و 50، و -100، و 1500، فيجب أن تكون المخرجات:

After creation:
Laptop: Price=999.99, Qty=50, Total=49999.50
After modifications:
Laptop: Price=0, Qty=1000, Total=0

لاحظ كيف أصبح السعر السالب 0 وتم تقييد الكمية 1500 لتصبح 1000. خصائصك تحمي الكائن من الحالات غير الصالحة - هذا هو مفهوم التغليف (encapsulation) في العمل!

ورقة مرجعية

تغلف الخصائص الحقول الخاصة مع وصول متحكم فيه من خلال موصلات get و set، مما يتيح التحقق من الصحة والكبسلة:

public class Temperature
{
    private double celsius;
    
    public double Celsius
    {
        get { return celsius; }
        set
        {
            if (value < -273.15)
                celsius = -273.15;
            else
                celsius = value;
        }
    }
}

يمكن للخصائص حساب القيم بناءً على الحقول الداخلية:

public double Fahrenheit
{
    get { return celsius * 9 / 5 + 32; }
    set { celsius = (value - 32) * 5 / 9; }
}

تتجاهل الخصائص المخصصة للقراءة فقط موصل set، مما يسمح فقط باسترجاع القيم المحسوبة أو المخزنة.

جرّب بنفسك

using System;
using Inventory;

class Program
{
    public static void Main(string[] args)
    {
        // قراءة المدخلات
        string name = Console.ReadLine();
        decimal initialPrice = Convert.ToDecimal(Console.ReadLine());
        int initialQuantity = Convert.ToInt32(Console.ReadLine());
        decimal newPrice = Convert.ToDecimal(Console.ReadLine());
        int newQuantity = Convert.ToInt32(Console.ReadLine());

        // TODO: إنشاء منتج (Product) باستخدام القيم الأولية
        
        // TODO: طباعة حالة المنتج بعد الإنشاء
        Console.WriteLine("After creation:");
        // تنسيق الطباعة: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
        
        // TODO: تعديل السعر والكمية بالقيم الجديدة
        
        // TODO: طباعة حالة المنتج بعد التعديلات
        Console.WriteLine("After modifications:");
        // تنسيق الطباعة: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
    }
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming