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

أمان الـ Null في الـ Classes

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

عند تصميم الأصناف، تحتاج إلى تحديد أي الحقول مطلوبة وأيها اختيارية. تؤثر سلامة القيم الفارغة (Null safety) على كيفية التصريح عن متغيرات النسخة (instance variables) وكتابة المنشئات (constructors).

يجب تهيئة الحقول غير القابلة للقيمة null قبل تشغيل جسم المنشئ. يمكنك القيام بذلك من خلال قوائم التهيئة، أو معاملات المنشئ، أو القيم الافتراضية:

class User {
  String name;           // يجب تهيئته
  String? bio;           // اختياري - يمكن أن يكون null
  int age = 0;           // له قيمة افتراضية
  
  User(this.name);       // يتم تهيئة name عبر المعامل
}

بالنسبة للحقول التي تقبل القيمة null، يمكنك تركها بدون تهيئة بما أنها تعود افتراضياً إلى null. هذا مفيد للبيانات الاختيارية:

class Product {
  String title;
  String? description;   // وصف اختياري للمنتج
  double? discount;      // لا يوجد خصم بشكل افتراضي
  
  Product(this.title);
}

var item = Product('Laptop');
print(item.description);  // null
print(item.discount);     // null

عند الوصول إلى الحقول القابلة للإلغاء (nullable fields)، استخدم العوامل المدركة للقيم الفارغة (null-aware operators) التي تعلمتها:

class Order {
  String id;
  User? customer;
  
  Order(this.id);
  
  String getCustomerName() {
    return customer?.name ?? 'Guest';
  }
}

تضمن الكلمة الأساسية required في المعلمات المسماة قيام المستدعين بتوفير القيم الأساسية:

class Account {
  String email;
  String? phone;
  
  Account({required this.email, this.phone});
}

var acc = Account(email: 'test@mail.com');  // الهاتف اختياري

من خلال الاختيار المدروس بين الحقول القابلة للإلغاء (nullable) وغير القابلة للإلغاء (non-nullable)، يمكنك إنشاء فئات (classes) توضح بوضوح أي البيانات أساسية وأيها اختيارية.

challenge icon

التحدي

سهل

دعنا نبني نظام حجز لفندق يوضح كيفية تصميم الفئات بمزيج مدروس من الحقول المطلوبة والاختيارية باستخدام ميزة سلامة القيم الخالية (null safety).

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

  • reservation.dart: قم بتعريف فئة Reservation التي تمثل حجز فندق. يحتاج كل حجز إلى معلومات أساسية معينة، ولكن بعض التفاصيل هي إضافات اختيارية قد يقدمها الضيوف أو لا يقدمونها. يجب أن تحتوي الفئة الخاصة بك على:
    • متغير String guestName غير قابل للقيمة الخالية - يجب أن يحتوي كل حجز على اسم ضيف
    • متغير int roomNumber غير قابل للقيمة الخالية - يجب تخصيص غرفة لكل حجز
    • متغير int nights غير قابل للقيمة الخالية مع قيمة افتراضية هي 1 - الحد الأدنى للإقامة هو ليلة واحدة
    • متغير String? specialRequests قابل للقيمة الخالية - قد يكون لدى الضيوف طلبات خاصة
    • متغير DateTime? checkInTime قابل للقيمة الخالية - قد لا يكون وقت الوصول الدقيق معروفاً
    • منشئ (constructor) يستخدم معاملات مسماة (named parameters) مع required لـ guestName و roomNumber، بينما يجب أن يكون nights اختيارياً مع قيمته الافتراضية
    • دالة getRequestsSummary() تعيد الطلبات الخاصة إذا تم توفيرها، أو 'No special requests' باستخدام عامل التشغيل ??
    • دالة getArrivalInfo() تعيد التمثيل النصي لوقت تسجيل الوصول باستخدام ?.، أو null إذا لم يتم تعيينه
    • دالة printConfirmation() تعرض تفاصيل الحجز
  • main.dart: قم باستيراد فئة الحجز الخاصة بك وإنشاء حجوزات تعرض مجموعات مختلفة من البيانات المطلوبة والاختيارية:
    • أنشئ حجزاً للضيف 'Sarah Johnson' في الغرفة 101 لمدة 3 ليالٍ، مع طلبات خاصة 'Late checkout' ووقت تسجيل وصول محدد بـ DateTime(2024, 6, 15, 14, 30)
    • أنشئ حجزاً للضيف 'Mike Chen' في الغرفة 205 (استخدم الليالي الافتراضية)، مع تعيين الطلبات الخاصة فقط إلى 'Extra pillows'
    • أنشئ حجزاً للضيف 'Emma Davis' في الغرفة 310 لمدة 2 ليلة (اترك كلا الحقلين الاختياريين كـ null)
    • لكل حجز بالترتيب، استدعِ printConfirmation()، ثم اطبع Arrival: [result] باستخدام getArrivalInfo()

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

=== Reservation Confirmed ===
Guest: [guestName]
Room: [roomNumber]
Nights: [nights]
Requests: [getRequestsSummary()]

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

=== Reservation Confirmed ===
Guest: Sarah Johnson
Room: 101
Nights: 3
Requests: Late checkout
Arrival: 2024-06-15 14:30:00.000
=== Reservation Confirmed ===
Guest: Mike Chen
Room: 205
Nights: 1
Requests: Extra pillows
Arrival: null
=== Reservation Confirmed ===
Guest: Emma Davis
Room: 310
Nights: 2
Requests: No special requests
Arrival: null

ورقة مرجعية

يجب تهيئة الحقول غير القابلة للإلغاء (Non-nullable) قبل تشغيل جسم المنشئ (constructor body)، بينما يمكن أن تظل الحقول القابلة للإلغاء (nullable) بدون تهيئة (تكون قيمتها الافتراضية null):

class User {
  String name;           // يجب تهيئته
  String? bio;           // اختياري - القيمة الافتراضية null
  int age = 0;           // لديه قيمة افتراضية
  
  User(this.name);
}

استخدم الحقول القابلة للإلغاء (nullable fields) للبيانات الاختيارية:

class Product {
  String title;
  String? description;   // اختياري
  double? discount;      // اختياري
  
  Product(this.title);
}

var item = Product('Laptop');
print(item.description);  // null

الوصول إلى الحقول القابلة للإلغاء باستخدام العوامل المدركة للقيم الفارغة (null-aware operators):

class Order {
  String id;
  User? customer;
  
  Order(this.id);
  
  String getCustomerName() {
    return customer?.name ?? 'Guest';
  }
}

استخدم الكلمة المفتاحية required في المعاملات المسماة (named parameters) للقيم الأساسية:

class Account {
  String email;
  String? phone;
  
  Account({required this.email, this.phone});
}

var acc = Account(email: 'test@mail.com');

جرّب بنفسك

import 'reservation.dart';

void main() {
  // TODO: 'Sarah Johnson' إنشاء حجز لـ
  // الغرفة 101، 3 ليالٍ، طلبات خاصة: 'Late checkout'
  // DateTime(2024, 6, 15, 14, 30) :وقت تسجيل الوصول
  
  // TODO: 'Mike Chen' إنشاء حجز لـ
  // الغرفة 205، استخدام عدد الليالي الافتراضي، طلبات خاصة: 'Extra pillows'
  // لم يتم تحديد وقت لتسجيل الوصول
  
  // TODO: 'Emma Davis' إنشاء حجز لـ
  // الغرفة 310، ليلتان، لا توجد طلبات خاصة، لا يوجد وقت لتسجيل الوصول
  
  // TODO: لكل حجز بالترتيب:
  // 1. printConfirmation() استدعاء
  // 2. getArrivalInfo() باستخدام 'Arrival: [result]' طباعة
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming