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

تعمق في Getters و Setters

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 33 من 110.

تصبح أدوات الجلب (Getters) والتعيين (setters) أدوات قوية للتغليف (encapsulation) عند دمجها مع الحقول الخاصة (private fields). فهي تتيح لك عرض واجهة عامة نظيفة مع الاحتفاظ بالتحكم الكامل في كيفية الوصول إلى البيانات وتعديلها.

من الأنماط الشائعة إقران حقل خاص (private field) مع دالة جلب (getter) ودالة تعيين (setter) عامتين تتضمنان التحقق من الصحة:

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

يمكن لدوال التعيين (Setters) فرض قواعد العمل، مما يضمن عدم دخول الكائن الخاص بك في حالة غير صالحة أبداً.

يمكنك أيضاً إنشاء getters محسوبة تستمد قيمها من بيانات خاصة:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;      // محسوبة
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

أحياناً قد ترغب في الوصول للقراءة فقط. ببساطة، قم بتوفير دالة جلب (getter) بدون دالة تعيين (setter):

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;  // للقراءة فقط
}

يوفر هذا النمط للكود الخارجي إمكانية رؤية البيانات مع منع أي تعديلات - فالحقل الخاص (private field) المقترن بـ getter فقط ينشئ وصولاً حقيقياً للقراءة فقط.

challenge icon

التحدي

سهل

لنقم ببناء نظام مخزون منتجات يستعرض قوة أدوات الحصول (getters) وأدوات التعيين (setters) للتحكم في الوصول إلى البيانات. ستقوم بإنشاء فئة (class) تحمي بياناتها الداخلية مع توفير خصائص محسوبة وتحقق من الصحة.

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

  • product.dart: قم بتعريف فئة Product تدير المخزون مع تغليف (encapsulation) مناسب. يجب أن يحتوي منتجك على:
    • متغير عام String name
    • متغير خاص double _price
    • متغير خاص int _quantity
    • منشئ (constructor) يأخذ القيم الثلاث جميعها
    • أداة الحصول price التي تعيد السعر الخاص
    • أداة التعيين price التي تقبل فقط القيم الأكبر من 0 (تجاهل القيم غير الصالحة)
    • أداة الحصول quantity التي تعيد الكمية الخاصة
    • أداة التعيين quantity التي تقبل فقط قيم 0 أو أكبر (تجاهل القيم السالبة)
    • أداة الحصول المحسوبة totalValue التي تعيد _price * _quantity
    • أداة الحصول المحسوبة isInStock التي تعيد true إذا كانت الكمية أكبر من 0
    • أداة الحصول للقراءة فقط sku التي تنشئ SKU بسيطاً عن طريق إرجاع أول 3 أحرف من الاسم بأحرف كبيرة متبوعة بالكمية (على سبيل المثال، LAP25 لـ "Laptop" بكمية 25)
    • دالة displayProduct() تعرض تفاصيل المنتج
  • main.dart: قم باستيراد فئة المنتج الخاصة بك ووضح كيف تتحكم أدوات الحصول والتعيين في الوصول:
    • أنشئ منتجاً باسم 'Laptop' بسعر 999.99 وكمية 25
    • استدعِ displayProduct()
    • اطبع In stock: [isInStock]
    • اطبع SKU: [sku]
    • حاول تعيين السعر إلى -50.0 (يجب تجاهله)
    • عين السعر إلى 899.99 (تغيير صالح)
    • حاول تعيين الكمية إلى -10 (يجب تجاهله)
    • عين الكمية إلى 0 (تغيير صالح)
    • استدعِ displayProduct()
    • اطبع In stock: [isInStock]
    • اطبع SKU: [sku]

يجب أن تطبع الدالة displayProduct() بهذا التنسيق:

--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]

المخرجات المتوقعة:

--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0

ورقة مرجعية

توفر أدوات الحصول (Getters) والتعيين (Setters) المدمجة مع الحقول الخاصة (private fields) تغليفاً (encapsulation) وتحكماً في الوصول إلى البيانات.

حقل خاص مع أداة الحصول والتعيين

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;
    } else {
      _celsius = value;
    }
  }
}

أدوات الحصول المحسوبة (Computed Getters)

يمكن لأدوات الحصول اشتقاق القيم من البيانات الخاصة:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

وصول للقراءة فقط

قم بتوفير أداة الحصول بدون أداة تعيين للخصائص التي تُقرأ فقط:

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;
}

جرّب بنفسك

import 'product.dart';

void main() {
  // TODO: قم بإنشاء منتج باسم 'Laptop' بسعر 999.99 وكمية 25

  // TODO: قم باستدعاء displayProduct()

  // TODO: "In stock: [isInStock]" قم بطباعة

  // TODO: "SKU: [sku]" قم بطباعة

  // TODO: حاول تعيين السعر إلى -50.0 (يجب تجاهله)

  // TODO: قم بتعيين السعر إلى 899.99 (تغيير صالح)

  // TODO: حاول تعيين الكمية إلى -10 (يجب تجاهله)

  // TODO: قم بتعيين الكمية إلى 0 (تغيير صالح)

  // TODO: قم باستدعاء displayProduct()

  // TODO: "In stock: [isInStock]" قم بطباعة

  // TODO: "SKU: [sku]" قم بطباعة
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming