1. مقدمة عن لغة دارت
دارت (Dart) هي لغة برمجة حديثة طورتها شركة جوجل، وهي اللغة الأساسية لتطوير تطبيقات Flutter. تتميز دارت بسهولة التعلم والقوة في الأداء.
مميزات لغة دارت:
- سهولة في التعلم والاستخدام
- أداء عالي وسرعة في التنفيذ
- دعم البرمجة كائنية التوجه(oop)
- إدارة ذاكرة تلقائية
- مكتبات غنية ومتنوعة
void main() {
print('أهلاً بك في عالم دارت!');
}
2. كل شيء عن المتغيرات
المتغيرات في دارت هي حاويات لتخزين البيانات. يمكن تعريف المتغيرات بطرق مختلفة:
طرق تعريف المتغيرات:
//من أجل إنشاء متغير جديد
type_variable name_variable = value_variable ;
//أمثلة
String firstName = 'hamza';
int age = 25 ;
خصائص المتغيرات:
- يمكن تغيير قيمتها بعد التعريف
- لها نوع بيانات محدد
- تحتاج إلى تهيئة قبل الاستخدام
- حساسة لحالة الأحرف
3. أنواع المتغيرات
دارت تدعم عدة أنواع من البيانات الأساسية:
| النوع | الوصف | مثال | شروط تغيير القيمة |
|---|---|---|---|
| int | الأعداد الصحيحة | int age = 25; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع int |
| double | الأعداد العشرية | double height = 175.5; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع double |
| String | النصوص | String name = "hamza"; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع String |
| bool | القيم المنطقية | bool isStudent = true; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع bool |
| List | القوائم | List<String> names = ['hamza', 'ahmed']; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع List |
| Map | الخرائط | Map<String, int> grades = {'ahmed': 85}; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نوع Map |
| var | يتخد نوع القيمة المخزنة فيه | var value = 'hamza'; | يمكن تغيير قيمتها بعد التعريف بشرط أن تكون من نفس نوع قيمته البدئية |
| dynamic | يتخد نوع القيمة المخزنة فيه | dynamic value = 'hamza'; | يمكن تغيير قيمتها بعد التعريف بأي نوع من المتغيرات |
void main() {
// أمثلة على أنواع المتغيرات
int studentCount = 30;
double average = 85.5;
String courseName = 'البرمجة بدارت';
bool isPassed = true;
List<String> students = ['أحمد', 'فاطمة', 'محمد'];
Map<String, double> grades = {
'ahmed': 88.5,
'fatima': 92.0,
'mohamed': 85.5
};
print('عدد الطلاب: $studentCount');
print('المعدل: $average');
}
4. كيفية تسمية المتغيرات
هناك قواعد وإرشادات مهمة لتسمية المتغيرات في دارت:
القواعد الإجبارية:
- يجب أن تبدأ بحرف صغير أو شرطة سفلية (_)
- لا يمكن أن تبدأ برقم
- لا تحتوي على مسافات
- لا تستخدم الكلمات المحجوزة
- حساسة لحالة الأحرف
الإرشادات المستحسنة:
// أسماء جيدة - camelCase
String firstName = 'أحمد';
int studentAge = 20;
bool isLoggedIn = false;
double accountBalance = 1500.50;
// أسماء للثوابت - SCREAMING_SNAKE_CASE
const int MAX_STUDENTS = 100;
const String API_URL = 'https://api.example.com';
// أسماء للمتغيرات الخاصة - تبدأ بـ _
String _privateData = 'بيانات خاصة';
int _internalCounter = 0;
// أمثلة على أسماء سيئة (تجنبها)
// String abc = 'غير واضح';
// int 123number = 10; // خطأ - يبدأ برقم
// bool class = true; // خطأ - كلمة محجوزة
5. دمج المتغيرات
هناك عدة طرق لدمج المتغيرات والنصوص في دارت:
1. استخدام علامة الدولار ($)
String firstName = 'أحمد';
String lastName = 'محمد';
int age = 25;
// الدمج باستخدام $
String introduction = 'اسمي $firstName $lastName وعمري $age سنة';
print(introduction);
// للتعبيرات المعقدة استخدم ${}
String message = 'العام القادم سأكون ${age + 1} سنة';
print(message);
2. استخدام علامة الجمع (+)
String greeting = 'مرحباً ' + firstName + ' ' + lastName;
String ageText = 'عمرك هو ' + age.toString() + ' سنة';
3. استخدام StringBuffer للدمج المتقدم
StringBuffer buffer = StringBuffer();
buffer.write('الاسم: ');
buffer.write(firstName);
buffer.write(' ');
buffer.write(lastName);
buffer.writeln(); // سطر جديد
buffer.write('العمر: ');
buffer.write(age);
String result = buffer.toString();
print(result);
4. دمج القوائم
List<String> names = ['أحمد', 'فاطمة', 'محمد'];
String allNames = names.join(', '); // 'أحمد, فاطمة, محمد'
print('الأسماء: $allNames');
6. التحويل بين أنواع المتغيرات
غالباً ما نحتاج لتحويل البيانات من نوع إلى آخر:
تحويل النصوص إلى أرقام
// تحويل النص إلى عدد صحيح
String ageText = '25';
int age = int.parse(ageText);
// تحويل النص إلى عدد عشري
String heightText = '175.5';
double height = double.parse(heightText);
// التحويل الآمن مع معالجة الأخطاء
String invalidNumber = 'abc';
int? result = int.tryParse(invalidNumber); // يعيد null إذا فشل
if (result != null) {
print('الرقم: $result');
} else {
print('فشل في التحويل');
}
تحويل الأرقام إلى نصوص
int count = 42;
double price = 99.99;
String countText = count.toString(); // '42'
String priceText = price.toString(); // '99.99'
// تنسيق الأرقام العشرية
String formattedPrice = price.toStringAsFixed(1); // '100.0'
print('السعر: $formattedPrice ريال');
تحويلات أخرى مفيدة
// تحويل بين int و double
int wholeNumber = 10;
double decimalNumber = wholeNumber.toDouble(); // 10.0
double floatNumber = 15.7;
int integerPart = floatNumber.toInt(); // 15
// تحويل القوائم
List<int> numbers = [1, 2, 3, 4, 5];
List<String> stringNumbers = numbers.map((n) => n.toString()).toList();
// تحويل إلى منطقي
String boolText = 'true';
bool boolValue = boolText.toLowerCase() == 'true';
7. جميع جوانب إدخال المستخدم
للحصول على إدخال من المستخدم، نستخدم حزمة dart:io:
import 'dart:io';
void main() {
// إدخال نص بسيط
print('ما اسمك؟');
String? name = stdin.readLineSync();
print('أهلاً $name!');
// إدخال رقم
print('كم عمرك؟');
String? ageInput = stdin.readLineSync();
int age = int.parse(ageInput ?? '0');
print('عمرك $age سنة');
// إدخال مع التحقق
int? validAge;
while (validAge == null) {
print('أدخل عمرك (رقم صحيح):');
String? input = stdin.readLineSync();
validAge = int.tryParse(input ?? '');
if (validAge == null) {
print('خطأ: يرجى إدخال رقم صحيح');
}
}
}
دوال مساعدة للإدخال الآمن
import 'dart:io';
// دالة للحصول على نص
String getStringInput(String prompt) {
print(prompt);
return stdin.readLineSync() ?? '';
}
// دالة للحصول على رقم صحيح
int getIntInput(String prompt) {
while (true) {
print(prompt);
String? input = stdin.readLineSync();
int? result = int.tryParse(input ?? '');
if (result != null) {
return result;
}
print('خطأ: يرجى إدخال رقم صحيح');
}
}
// دالة للحصول على رقم عشري
double getDoubleInput(String prompt) {
while (true) {
print(prompt);
String? input = stdin.readLineSync();
double? result = double.tryParse(input ?? '');
if (result != null) {
return result;
}
print('خطأ: يرجى إدخال رقم صالح');
}
}
void main() {
String name = getStringInput('ما اسمك؟');
int age = getIntInput('كم عمرك؟');
double height = getDoubleInput('ما طولك بالسنتيمتر؟');
print('الاسم: $name');
print('العمر: $age سنة');
print('الطول: $height سم');
}
8. تعريف const و final والفروقات بينهما
كلاهما يستخدم لإنشاء متغيرات لا يمكن تغييرها، لكن هناك فروقات مهمة:
const - الثوابت وقت الترجمة
// const يجب أن تكون قيمتها معروفة وقت الترجمة
const String appName = 'تطبيق دارت';
const int maxUsers = 1000;
const double pi = 3.14159;
// يمكن استخدامها في التعبيرات الثابتة
const int secondsInMinute = 60;
const int minutesInHour = 60;
const int secondsInHour = secondsInMinute * minutesInHour; // 3600
// للقوائم والخرائط الثابتة
const List<String> weekDays = [
'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء',
'الخميس', 'الجمعة', 'السبت'
];
const Map<String, String> colors = {
'أحمر': '#FF0000',
'أخضر': '#00FF00',
'أزرق': '#0000FF'
};
final - الثوابت وقت التنفيذ
// final يمكن تحديد قيمتها وقت التنفيذ
final String currentTime = DateTime.now().toString();
final int randomNumber = (1000 * 0.5).round();
// يمكن تهيئتها لاحقاً
final String userName;
// ... كود آخر
userName = 'أحمد محمد'; // يتم تحديدها مرة واحدة فقط
// للكائنات المعقدة
final List<String> dynamicList = [];
dynamicList.add('عنصر 1'); // يمكن تعديل محتوى القائمة
dynamicList.add('عنصر 2');
// dynamicList = []; // خطأ - لا يمكن إعادة تعيين المتغير
جدول المقارنة
| الخاصية | const | final |
|---|---|---|
| وقت التحديد | وقت الترجمة | وقت التنفيذ |
| إعادة التعيين | غير مسموح | غير مسموح |
| تعديل المحتوى | غير مسموح | مسموح للكائنات القابلة للتغيير |
| استهلاك الذاكرة | أقل (نسخة واحدة) | عادي |
9. المنطق والعوامل العلائقية
العوامل المنطقية والعلائقية أساسية لبناء الشروط والقرارات:
نوع bool
bool isStudent = true;
bool isGraduated = false;
bool isOnline = true;
// يمكن تحديدها من خلال التعبيرات
int age = 20;
bool isAdult = age >= 18; // true
bool isChild = age < 13; // false
العوامل العلائقية (Relational Operators)
int a = 10;
int b = 20;
// المقارنة
bool isEqual = (a == b); // false - متساوي
bool isNotEqual = (a != b); // true - غير متساوي
bool isGreater = (a > b); // false - أكبر من
bool isLess = (a < b); // true - أصغر من
bool isGreaterEqual = (a >= b); // false - أكبر من أو يساوي
bool isLessEqual = (a <= b); // true - أصغر من أو يساوي
print('$a == $b: $isEqual');
print('$a != $b: $isNotEqual');
print('$a > $b: $isGreater');
print('$a < $b: $isLess');
العوامل المنطقية (Logical Operators)
bool hasLicense = true;
bool hasInsurance = false;
int age = 22;
// AND (&&) - يجب أن تكون كلا الحالتين صحيحتين
bool canDriveAnd = hasLicense && (age >= 18); // true
bool canDriveAll = hasLicense && hasInsurance && (age >= 18); // false
// OR (||) - يكفي أن تكون إحدى الحالتين صحيحة
bool hasDocument = hasLicense || hasInsurance; // true
// NOT (!) - عكس القيمة المنطقية
bool doesntHaveLicense = !hasLicense; // false
bool isMinor = !(age >= 18); // false
print('يمكن القيادة: $canDriveAnd');
print('لديه وثيقة: $hasDocument');
print('قاصر: $isMinor');
أمثلة عملية
// فحص صحة كلمة المرور
String password = 'MyPass123';
bool isLongEnough = password.length >= 8;
bool hasUpperCase = password.contains(RegExp(r'[A-Z]'));
bool hasLowerCase = password.contains(RegExp(r'[a-z]'));
bool hasDigit = password.contains(RegExp(r'\d'));
10. شروط if
جمل الشرط تتيح لنا تنفيذ كود مختلف بناءً على شروط معينة:
الشرط البسيط if
int age = 18;
if (age >= 18) {
print('أنت بالغ');
}
// شرط بدون أقواس للسطر الواحد
if (age >= 18) print('يمكنك القيادة');
if-else الشرط مع البديل
int score = 75;
if (score >= 60) {
print('نجحت في الامتحان');
} else {
print('للأسف، لم تنجح');
}
// تحديد مستوى الدرجة
if (score >= 90) {
print('ممتاز');
} else if (score >= 80) {
print('جيد جداً');
} else if (score >= 70) {
print('جيد');
} else if (score >= 60) {
print('مقبول');
} else {
print('راسب');
}
الشروط المعقدة
String username = 'أحمد';
String password = '12345';
bool isLoggedIn = false;
// شرط مركب
if (username.isNotEmpty && password.length >= 5) {
if (username == 'أحمد' && password == '12345') {
isLoggedIn = true;
print('تم تسجيل الدخول بنجاح');
} else {
print('اسم المستخدم أو كلمة المرور خاطئة');
}
} else {
print('يرجى إدخال بيانات صحيحة');
}
// شرط بالعامل الثلاثي (Ternary Operator)
String message = isLoggedIn ? 'مرحباً $username' : 'يرجى تسجيل الدخول';
print(message);
التحقق من null
String? userName; // قابل للقيمة null
// التحقق التقليدي
if (userName != null) {
print('اسم المستخدم: $userName');
} else {
print('لم يتم تعيين اسم المستخدم');
}
// استخدام null-aware operators
// تعيين قيمة افتراضية إذا كانت null
userName ??= 'ضيف ';
print('أهلاً ${userName ?? "ضيف"}');
// Safe navigation
String? email = null;
// لن يسبب خطأ حتى لو كانت null
int? emailLength = email?.length;
// قيمة افتراضية عند العرض
print('طول الايميل: ${emailLength ?? "غير محدد"}');
switch-case للشروط المتعددة
String day = 'الاثنين';
switch (day) {
case 'السبت':
case 'الأحد':
print('عطلة نهاية الأسبوع');
break;
case 'الاثنين':
print('بداية الأسبوع');
break;
case 'الثلاثاء':
case 'الأربعاء':
case 'الخميس':
print('منتصف الأسبوع');
break;
case 'الجمعة':
print('آخر يوم عمل');
break;
default:
print('يوم غير معروف');
}
// switch expression (في Dart 3.0+)
String dayType = switch (day) {
'السبت' || 'الأحد' => 'عطلة',
'الاثنين' => 'بداية الأسبوع',
'الجمعة' => 'نهاية الأسبوع',
_ => 'يوم عادي'
};
print('نوع اليوم: $dayType');
11. جميع أنواع الحلقات التكرارية
الحلقات التكرارية تتيح لنا تنفيذ كود متكرر بفعالية:
حلقة for التقليدية
// الشكل الأساسي
for (int i = 0; i < 5; i++) {
print('الرقم: $i');
}
// عد تنازلي
for (int i = 10; i >= 1; i--) {
print('العد التنازلي: $i');
}
// خطوات مختلفة
for (int i = 0; i <= 20; i += 2) {
print('الأرقام الزوجية: $i');
}
// حلقات متداخلة - طباعة جدول الضرب
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
print('$i × $j = ${i * j}');
}
print('---');
}
حلقة for-in للمجموعات
// للقوائم
List fruits = ['تفاح', 'موز', 'برتقال', 'عنب'];
for (String fruit in fruits) {
print('الفاكهة: $fruit');
}
// للخرائط
Map grades = {
'أحمد': 85,
'فاطمة': 92,
'محمد': 78
};
for (String student in grades.keys) {
print('$student: ${grades[student]}');
}
// للنصوص (كل حرف)
String word = 'مرحبا';
for (String char in word.split('')) {
print('الحرف: $char');
}
حلقة while
// while الأساسية
int counter = 0;
while (counter < 5) {
print('العداد: $counter');
counter++;
}
// مثال عملي - البحث في قائمة
List numbers = [1, 5, 8, 12, 15, 20];
int target = 12;
int index = 0;
bool found = false;
while (index < numbers.length && !found) {
if (numbers[index] == target) {
found = true;
print('وُجد الرقم $target في الموضع $index');
}
index++;
}
if (!found) {
print('لم يُوجد الرقم $target');
}
// حلقة لا نهائية مع شرط الخروج
while (true) {
print('أدخل "خروج" للإنهاء:');
String? input = stdin.readLineSync();
if (input?.toLowerCase() == 'خروج') {
break;
}
print('كتبت: $input');
}
حلقة do-while
// تنفذ مرة واحدة على الأقل
int attempts = 0;
String? password;
do {
attempts++;
print('أدخل كلمة المرور (المحاولة $attempts):');
password = stdin.readLineSync();
if (password != 'سري123') {
print('كلمة مرور خاطئة');
}
} while (password != 'سري123' && attempts < 3);
if (password == 'سري123') {
print('تم تسجيل الدخول بنجاح');
} else {
print('تم استنفاد المحاولات');
}
// مثال آخر - قائمة طعام
int choice;
do {
print('--- القائمة ---');
print('1. إضافة عنصر');
print('2. عرض العناصر');
print('3. حذف عنصر');
print('0. خروج');
print('اختر رقماً:');
choice = int.tryParse(stdin.readLineSync() ?? '') ?? -1;
switch (choice) {
case 1:
print('تم اختيار إضافة عنصر');
break;
case 2:
print('تم اختيار عرض العناصر');
break;
case 3:
print('تم اختيار حذف عنصر');
break;
case 0:
print('شكراً لاستخدام البرنامج');
break;
default:
print('خيار غير صحيح');
}
} while (choice != 0);
كلمات التحكم في الحلقات
// break - للخروج من الحلقة
for (int i = 1; i <= 10; i++) {
if (i == 5) {
print('توقف عند $i');
break; // يخرج من الحلقة
}
print('الرقم: $i');
}
// continue - لتخطي التكرار الحالي
print('\nالأرقام الفردية فقط:');
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // يتخطى الأرقام الزوجية
}
print('رقم فردي: $i');
}
// Label للحلقات المتداخلة
outer: for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
print('خروج من كلا الحلقتين');
break outer; // يخرج من الحلقة الخارجية
}
print('i=$i, j=$j');
}
}
12. الدوال في دارت
الدوال هي كتل من الكود يمكن إعادة استخدامها وتنظيم البرنامج:
الدوال الأساسية
// دالة بسيطة بدون معاملات ولا ترجع قيمة
void sayHello() {
print('أهلاً وسهلاً!');
}
// دالة ترجع قيمة
String getGreeting() {
return 'مرحباً بك في عالم دارت';
}
// دالة بمعاملات
int addNumbers(int a, int b) {
return a + b;
}
// دالة بمعاملات اختيارية
void printInfo(String name, [int? age, String? city]) {
print('الاسم: $name');
if (age != null) print('العمر: $age');
if (city != null) print('المدينة: $city');
}
// استخدام الدوال
void main() {
sayHello();
String greeting = getGreeting();
print(greeting);
int sum = addNumbers(10, 20);
print('المجموع: $sum');
printInfo('أحمد');
printInfo('فاطمة', 25);
printInfo('محمد', 30, 'الرياض');
}
المعاملات المسماة
// معاملات مسماة اختيارية
void createUser({String? name, int? age, String? email, bool isActive = true}) {
print('--- معلومات المستخدم ---');
print('الاسم: ${name ?? "غير محدد"}');
print('العمر: ${age ?? "غير محدد"}');
print('الايميل: ${email ?? "غير محدد"}');
print('نشط: $isActive');
}
// معاملات مسماة مطلوبة
void registerUser({required String username, required String password, String? email}) {
print('تم تسجيل المستخدم: $username');
if (email != null) {
print('الايميل: $email');
}
}
// الاستخدام
void main() {
createUser();
createUser(name: 'أحمد');
createUser(name: 'فاطمة', age: 25, email: 'fatima@example.com');
registerUser(username: 'ahmed123', password: 'mypass');
registerUser(username: 'fatima456', password: 'herpass', email: 'fatima@example.com');
}
الدوال المختصرة (Arrow Functions)
// للدوال البسيطة من سطر واحد
int square(int x) => x * x;
bool isEven(int number) => number % 2 == 0;
String formatName(String firstName, String lastName) => '$firstName $lastName';
// دوال مع معاملات مسماة
double calculateArea({required double width, required double height}) => width * height;
// استخدام
void main() {
print('مربع 5: ${square(5)}'); // 25
print('هل 4 زوجي؟ ${isEven(4)}'); // true
print('الاسم الكامل: ${formatName("أحمد", "محمد")}');
print('المساحة: ${calculateArea(width: 10, height: 5)}');
}
الدوال عالية المستوى (Higher-Order Functions)
// دالة تأخذ دالة أخرى كمعامل
void executeOperation(int a, int b, int Function(int, int) operation) {
int result = operation(a, b);
print('النتيجة: $result');
}
// دالة ترجع دالة أخرى
Function(int, int) getOperation(String operationType) {
switch (operationType) {
case 'add':
return (int a, int b) => a + b;
case 'multiply':
return (int a, int b) => a * b;
case 'subtract':
return (int a, int b) => a - b;
default:
return (int a, int b) => 0;
}
}
// استخدام مع الدوال المجهولة
void main() {
// استخدام دالة محددة مسبقاً
executeOperation(10, 5, addNumbers);
// استخدام دالة مجهولة
executeOperation(10, 5, (int x, int y) => x * y);
// الحصول على دالة من دالة أخرى
var addFunc = getOperation('add');
print('10 + 5 = ${addFunc(10, 5)}');
// استخدام مع القوائم
List numbers = [1, 2, 3, 4, 5];
// map - تحويل كل عنصر
List doubled = numbers.map((n) => n * 2).toList();
print('الأرقام المضاعفة: $doubled');
// where - تصفية العناصر
List evenNumbers = numbers.where((n) => n % 2 == 0).toList();
print('الأرقام الزوجية: $evenNumbers');
// forEach - تنفيذ عملية على كل عنصر
numbers.forEach((n) => print('الرقم: $n'));
}
الدوال العكسية (Recursive Functions)
// حساب المضروب
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
// تسلسل فيبوناتشي
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
// البحث الثنائي
int binarySearch(List sortedList, int target, [int start = 0, int? end]) {
end ??= sortedList.length - 1;
if (start > end) {
return -1; // لم يتم العثور على العنصر
}
int mid = (start + end) ~/ 2;
if (sortedList[mid] == target) {
return mid;
} else if (sortedList[mid] > target) {
return binarySearch(sortedList, target, start, mid - 1);
} else {
return binarySearch(sortedList, target, mid + 1, end);
}
}
void main() {
print('مضروب 5: ${factorial(5)}'); // 120
print('فيبوناتشي للرقم 7: ${fibonacci(7)}'); // 13
List sortedNumbers = [1, 3, 5, 7, 9, 11, 13, 15];
int index = binarySearch(sortedNumbers, 7);
print('الرقم 7 موجود في الموضع: $index');
}
13. جميع جوانب البرمجة كائنية التوجه في دارت
دارت لغة كائنية التوجه بالكامل، وتدعم جميع المفاهيم الأساسية للـ OOP:
الفئات الأساسية (Basic Classes)
// تعريف فئة بسيطة
class Person {
// خصائص الفئة
String name;
int age;
String? email; // اختيارية
// منشئ (Constructor)
Person(this.name, this.age, [this.email]);
// منشئ مسمى
Person.withEmail({required this.name, required this.age, required this.email});
// منشئ للضيف
Person.guest() : name = 'ضيف', age = 0;
// دوال الفئة (Methods)
void introduce() {
print('أهلاً، اسمي $name وعمري $age سنة');
if (email != null) {
print('يمكنكم التواصل معي على: $email');
}
}
bool isAdult() {
return age >= 18;
}
void celebrateBirthday() {
age++;
print('عيد ميلاد سعيد! أصبح عمري $age سنة');
}
// تمثيل نصي للكائن
@override
String toString() {
return 'Person(name: $name, age: $age, email: $email)';
}
}
// استخدام الفئة
void main() {
// إنشاء كائنات مختلفة
Person person1 = Person('أحمد', 25);
Person person2 = Person.withEmail(name: 'فاطمة', age: 22, email: 'fatima@example.com');
Person guest = Person.guest();
person1.introduce();
person2.introduce();
guest.introduce();
print('هل أحمد بالغ؟ ${person1.isAdult()}');
person1.celebrateBirthday();
}
الوراثة (Inheritance)
// الفئة الأساسية
class Animal {
String name;
String species;
int age;
Animal(this.name, this.species, this.age);
void eat() {
print('$name يأكل');
}
void sleep() {
print('$name ينام');
}
void makeSound() {
print('$name يصدر صوتاً');
}
@override
String toString() => '$species اسمه $name';
}
// فئة مشتقة - القط
class Cat extends Animal {
String furColor;
Cat(String name, int age, this.furColor) : super(name, 'قط', age);
// إعادة تعريف دالة من الفئة الأساسية
@override
void makeSound() {
print('$name يموء: مياو مياو');
}
// دالة خاصة بالقطط
void purr() {
print('$name يخرخر بسعادة');
}
void scratch() {
print('$name يحك أظافره');
}
}
// فئة مشتقة - الكلب
class Dog extends Animal {
String breed;
Dog(String name, int age, this.breed) : super(name, 'كلب', age);
@override
void makeSound() {
print('$name ينبح: هاو هاو');
}
void wagTail() {
print('$name يهز ذيله');
}
void fetch() {
print('$name يجلب الكرة');
}
}
void main() {
Cat myCat = Cat('قطقوط', 3, 'برتقالي');
Dog myDog = Dog('بوبي', 5, 'جولدن ريتريفر');
print(myCat);
myCat.eat();
myCat.makeSound();
myCat.purr();
print('\n${myDog}');
myDog.eat();
myDog.makeSound();
myDog.wagTail();
}
التجريد (Abstract Classes) والواجهات (Interfaces)
// فئة مجردة
abstract class Shape {
String name;
Shape(this.name);
// دالة مجردة يجب تنفيذها في الفئات المشتقة
double calculateArea();
double calculatePerimeter();
// دالة عادية يمكن استخدامها
void displayInfo() {
print('الشكل: $name');
print('المساحة: ${calculateArea()}');
print('المحيط: ${calculatePerimeter()}');
}
}
// واجهة (Interface)
abstract class Drawable {
void draw();
void erase();
}
// تنفيذ الفئة المجردة والواجهة
class Rectangle extends Shape implements Drawable {
double width;
double height;
Rectangle(this.width, this.height) : super('مستطيل');
@override
double calculateArea() => width * height;
@override
double calculatePerimeter() => 2 * (width + height);
@override
void draw() {
print('رسم مستطيل بعرض $width وارتفاع $height');
}
@override
void erase() {
print('مسح المستطيل');
}
}
class Circle extends Shape implements Drawable {
double radius;
Circle(this.radius) : super('دائرة');
@override
double calculateArea() => 3.14159 * radius * radius;
@override
double calculatePerimeter() => 2 * 3.14159 * radius;
@override
void draw() {
print('رسم دائرة بنصف قطر $radius');
}
@override
void erase() {
print('مسح الدائرة');
}
}
void main() {
List shapes = [
Rectangle(10, 5),
Circle(7),
];
for (Shape shape in shapes) {
shape.displayInfo();
// التحقق من النوع والتحويل
if (shape is Drawable) {
shape.draw();
}
print('---');
}
}
التغليف (Encapsulation) والخصائص الخاصة
// التغليف (Encapsulation) والخصائص الخاصة
class BankAccount {
String _accountNumber; // خاصية خاصة (تبدأ بـ _)
String _holderName;
double _balance;
// Constructor
BankAccount(this._accountNumber, this._holderName, this._balance);
// Getters للوصول للخصائص الخاصة
String get accountNumber => _accountNumber;
String get holderName => _holderName;
double get balance => _balance;
// Setter مع التحقق من صحة البيانات
set holderName(String name) {
if (name.isNotEmpty) {
_holderName = name;
} else {
throw ArgumentError('اسم صاحب الحساب لا يمكن أن يكون فارغاً');
}
}
// دوال للعمليات المصرفية
bool withdraw(double amount) {
if (amount <= 0) {
print('مبلغ السحب يجب أن يكون أكبر من صفر');
return false;
}
if (amount > _balance) {
print('الرصيد غير كافي');
return false;
}
_balance -= amount;
print('تم سحب $amount ريال. الرصيد الحالي: $_balance ريال');
return true;
}
void deposit(double amount) {
if (amount <= 0) {
print('مبلغ الإيداع يجب أن يكون أكبر من صفر');
return;
}
_balance += amount;
print('تم إيداع $amount ريال. الرصيد الحالي: $_balance ريال');
}
void displayAccountInfo() {
print('--- معلومات الحساب ---');
print('رقم الحساب: $_accountNumber');
print('اسم صاحب الحساب: $_holderName');
print('الرصيد: $_balance ريال');
}
// دالة إضافية لتحويل الأموال
bool transfer(BankAccount targetAccount, double amount) {
if (amount <= 0) {
print('مبلغ التحويل يجب أن يكون أكبر من صفر');
return false;
}
if (amount > _balance) {
print('الرصيد غير كافي للتحويل');
return false;
}
_balance -= amount;
targetAccount._balance += amount;
print('تم تحويل $amount ريال إلى حساب ${targetAccount._holderName}');
print('رصيدك الحالي: $_balance ريال');
return true;
}
}
void main() {
// إنشاء حساب جديد
BankAccount account = BankAccount('123456789', 'أحمد محمد', 5000);
// عرض معلومات الحساب
account.displayAccountInfo();
print('');
// إيداع مبلغ
account.deposit(1000);
print('');
// سحب مبلغ
account.withdraw(2000);
print('');
// محاولة سحب مبلغ أكبر من الرصيد
account.withdraw(10000);
print('');
// تغيير اسم صاحب الحساب
account.holderName = 'أحمد علي محمد';
print('تم تحديث اسم صاحب الحساب');
print('');
// إنشاء حساب آخر للتحويل
BankAccount account2 = BankAccount('987654321', 'فاطمة أحمد', 2000);
// تحويل مبلغ بين الحسابات
account.transfer(account2, 500);
print('');
// عرض معلومات الحسابين
print('=== الحساب الأول ===');
account.displayAccountInfo();
print('');
print('=== الحساب الثاني ===');
account2.displayAccountInfo();
// مثال على استخدام الـ Getters
print('');
print('الوصول للبيانات باستخدام الـ Getters:');
print('رقم الحساب الأول: ${account.accountNumber}');
print('اسم صاحب الحساب الأول: ${account.holderName}');
print('رصيد الحساب الأول: ${account.balance} ريال');
}
14. التعامل مع الاستثناءات
الاستثناءات (Exceptions) تُستخدم لمعالجة الأخطاء أثناء تنفيذ البرنامج. يمكنك استخدام try-catch للقبض على الأخطاء والتعامل معها.
// مثال على try-catch
void main() {
try {
int result = 10 ~/ 0; // محاولة القسمة على صفر
print(result);
} catch (e) {
print('حدث خطأ: 0e');
}
}
- try: الكود الذي قد ينتج عنه خطأ.
- catch: الكود الذي ينفذ عند حدوث خطأ.
15. البرمجة غير المتزامنة (Asynchronous Programming)
تُستخدم البرمجة غير المتزامنة للتعامل مع العمليات التي تستغرق وقتاً طويلاً مثل جلب البيانات من الإنترنت.
// مثال على Future و async/await
Future fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'تم جلب البيانات!';
}
void main() async {
print('جاري جلب البيانات...');
String result = await fetchData();
print(result);
}
- Future: يمثل عملية ستكتمل في المستقبل.
- async: تُستخدم مع الدوال التي تحتوي على عمليات غير متزامنة.
- await: تنتظر انتهاء العملية قبل الانتقال للسطر التالي.