Dart: فئات Dart والكائنات — جوهر البرمجة الكائنية

آخر تحديث: 2026-08-26

الفئة هي مخطط للكائنات — مخطط جيد يصنع كائنات جيدة، وكائنات جيدة تبني أنظمة جيدة.

1. ما ستتعلمه


2. قصة مطور حقيقي

(1) نقطة الألم: نسخ ولصق الكود في 5 فئات — كل تغيير يحتاج 5 تعديلات

كتب توم 5 فئات: User, Admin, Guest, Moderator, SuperAdmin. لكل واحدة: name, email, createdAt, login(), logout(), printInfo(). 50 سطر متكرر. عندما طلب المدير "أضف phone"، كان عليه تعديل 5 فئات. نسخ ولصق متكرر. سأل زميله: "استخدم الوراثة."

(2) حل Dart

DART
// ❌ كود سيء — نسخ ولصق
class User {
  String name, email;
  DateTime createdAt;
  void login() { /* ... */ }
  void logout() { /* ... */ }
  void printInfo() { print('$name, $email'); }
}

class Admin {
  String name, email;
  DateTime createdAt;
  void login() { /* ... */ }  // نفس كود User
  void logout() { /* ... */ }  // نفس كود User
  void printInfo() { print('$name, $email'); }
}

// ✅ مع الوراثة
class User {
  final String name;
  final String email;
  final DateTime createdAt;
  User(this.name, this.email) : createdAt = DateTime.now();
  void login() { print('$name logged in'); }
  void logout() { print('$name logged out'); }
  void printInfo() => print('$name ($email)');
}

class Admin extends User {
  Admin(String name, String email) : super(name, email);
  void banUser(User user) { print('Admin $name banned ${user.name}'); }
}

(3) النتيجة: 5 فئات × 50 سطر = 250 سطر → 1 فئة أساسية + 5 فئات فرعية

المؤشر نسخ ولصق وراثة
عدد أسطر الكود 250 80
وقت إضافة حقل جديد 5 فئات 1 فئة + تعديل تلقائي
الأخطاء الناجمة عن عدم الاتساق 3/شهر 0
وقت الصيانة 4 ساعات 30 دقيقة
TEXT 📖 للعرض فقط
قبل: 5 فئات × 50 سطر، 3 أخطاء/شهر
بعد: 1 فئة أساسية + 5 فئات فرعية، 0 أخطاء
ROI: تقليل الكود 68%

3. إعلان الفئة الأساسي

(1) فئة بسيطة

DART
// إعلان الفئة
class User {
  // الخصائص (الحقول)
  String name = 'غير معروف';
  int age = 0;
  String? email;
}

// إنشاء كائن
final user1 = User();
print(user1.name);  // 'غير معروف'
print(user1.age);   // 0

// تعيين الخصائص
user1.name = 'Bob';
user1.age = 25;
print(user1.name);  // 'Bob'

(2) خصائص final

DART
// final — لا يمكن تغيير القيمة بعد التعيين
class Point {
  final double x;
  final double y;

  Point(this.x, this.y);
}

final p = Point(3.0, 4.0);
print('(${p.x}, ${p.y})');  // (3.0, 4.0)
// p.x = 5.0;  // ❌ خطأ في وقت الترجمة

(3) خصائص late

DART
class Database {
  late String connectionString;
  late List<String> tables;

  void connect() {
    connectionString = 'postgresql://localhost';
    tables = ['users', 'orders'];
  }
}

final db = Database();
// db.tables;  // ❌ خطأ في وقت التشغيل: لم تتم تهيئة LateInitializationError
db.connect();
print(db.tables);  // ['users', 'orders']

(4) خصائص ثابتة (static)

DART
class Counter {
  static int count = 0;  // مشترك بين جميع الكائنات

  Counter() {
    count++;
  }
}

final c1 = Counter();
final c2 = Counter();
final c3 = Counter();

print(Counter.count);  // 3 (وليس 1)

(5) getter و setter

DART
class Circle {
  double _radius;  // خاص (يبدأ بـ _)

  Circle(this._radius);

  // getter
  double get radius => _radius;
  double get area => 3.14159 * _radius * _radius;
  double get circumference => 2 * 3.14159 * _radius;

  // setter
  set radius(double value) {
    if (value < 0) {
      throw ArgumentError('Radius cannot be negative');
    }
    _radius = value;
  }
}

final c = Circle(5.0);
print('radius: ${c.radius}');                // 5.0
print('area: ${c.area}');                    // 78.54
print('circumference: ${c.circumference}');  // 31.42
c.radius = 10.0;
print('new area: ${c.area}');                // 314.16

▶ مثال: فئة Temperature بسيطة

DART
class Temperature {
  double _celsius;

  Temperature(this._celsius);

  // getter
  double get celsius => _celsius;
  double get fahrenheit => _celsius * 9 / 5 + 32;
  double get kelvin => _celsius + 273.15;

  // setter
  set celsius(double value) {
    if (value < -273.15) {
      throw ArgumentError('Below absolute zero');
    }
    _celsius = value;
  }
}

void main() {
  final t = Temperature(25);
  print('${t.celsius}°C = ${t.fahrenheit}°F = ${t.kelvin}K');
  // 25.0°C = 77.0°F = 298.15K
}
TEXT 📖 للعرض فقط
> **الإخراج:** فئة Temperature مع getter/setter — الوصول من خلال الخصائص، وليس الحقول.

4. 5 أنواع من المُنشئات

(1) المُنشئ الافتراضي (Default)

DART
class Point {
  double x, y;

  // مُنشئ افتراضي بدون معاملات
  Point() {
    x = 0;
    y = 0;
  }

  // مُنشئ بمعاملات
  Point(this.x, this.y);
}

final p1 = Point();       // (0, 0)
final p2 = Point(3, 4);   // (3, 4)

(2) المُنشئات المسماة (Named)

DART
class User {
  final String name;
  final int age;
  final String? email;
  final DateTime? createdAt;

  // المُنشئ الافتراضي
  User(this.name, this.age);

  // مُنشئ مسمى
  User.withEmail(String name, int age, this.email) : createdAt = DateTime.now();

  // مُنشئ مسمى آخر
  User.guest() : name = 'Guest', age = 0;

  // مُنشئ مسمى مع تعيين قائمة المعلمات
  User.admin({
    required String name,
    required this.email,
  })  : age = 99,
        createdAt = DateTime.now();
}

final u1 = User('Bob', 25);
final u2 = User.withEmail('Bob', 25, 'bob@example.com');
final u3 = User.guest();
final u4 = User.admin(name: 'Alice', email: 'admin@example.com');

(3) مُنشئات التهيئة (Initializer)

DART
class User {
  final String name;
  final int age;
  final DateTime createdAt;

  // initializer list — تنفيذ قبل جسم المُنشئ
  User(this.name, this.age) : createdAt = DateTime.now();

  // مع التحقق
  User.checked(this.name, this.age)
      : age = age >= 0 ? age : throw ArgumentError('Age must be non-negative'),
        createdAt = DateTime.now();

  // مع تحويل
  User.fromJson(Map<String, dynamic> json)
      : name = json['name'] as String,
        age = json['age'] as int,
        createdAt = DateTime.parse(json['createdAt'] as String);
}

final u1 = User('Bob', 25);
final u2 = User.checked('Bob', 25);
final u3 = User.fromJson({
  'name': 'Bob',
  'age': 25,
  'createdAt': '2026-07-27T10:00:00Z',
});

(4) مُنشئات المُصنّع (Factory)

DART
class Logger {
  final String name;
  static final Map<String, Logger> _cache = {};

  // مُنشئ عادي
  Logger._internal(this.name);

  // مُنشئ مُصنّع — يُرجع كائن مخزن مؤقتًا
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }
}

final log1 = Logger('app');
final log2 = Logger('app');
print(identical(log1, log2));  // true (نفس الكائن)

(5) مُنشئات إعادة التوجيه (Redirecting)

DART
class User {
  final String name;
  final int age;

  User(this.name, this.age);

  // إعادة توجيه إلى مُنشئ آخر
  User.guest() : this('Guest', 0);

  // إعادة توجيه مع قائمة المعلمات
  User.admin() : this('Admin', 99);
}

final u1 = User.guest();  // User('Guest', 0)
final u2 = User.admin();  // User('Admin', 99)

(6) مُنشئات الثابتة (Const)

DART
class Color {
  final int r, g, b;

  // مُنشئ const — يجب أن تكون جميع المعلمات ثابتة
  const Color(this.r, this.g, this.b);

  static const red = Color(255, 0, 0);
  static const green = Color(0, 255, 0);
  static const blue = Color(0, 0, 255);
  static const white = Color(255, 255, 255);
  static const black = Color(0, 0, 0);
}

// const يجب أن يكون const
final c1 = const Color(128, 128, 128);
const c2 = Color(255, 0, 0);  // ثابت وقت الترجمة

(7) const vs final

DART
class Point {
  final double x, y;
  const Point(this.x, this.y);
}

const p1 = Point(1.0, 2.0);  // const — وقت الترجمة
final p2 = Point(1.0, 2.0);  // final — وقت التشغيل
// const p3 = Point(DateTime.now().millisecondsSinceEpoch.toDouble(), 0);  // ❌ لا يمكن const

(8) جدول المقارنة

المُنشئ بناء الجملة متى يُستخدم
الافتراضي ClassName(params) { ... } التهيئة البسيطة
المسمى ClassName.named(params) { ... } واجهات برمجة متعددة
التهيئة ClassName(params) : field = expr التحقق والتحويل
المُصنّع factory ClassName(params) { ... } Singleton, ذاكرة مخبأة
إعادة التوجيه ClassName.name() : this(args) واجهة موحدة
الثابت const ClassName(params) قيم ثابتة وقت الترجمة

▶ مثال: نظام نماذج البيانات

DART
// عدة طرق لإنشاء User
class User {
  final String id;
  final String name;
  final String email;
  final int age;
  final DateTime createdAt;
  final Map<String, dynamic>? metadata;

  // المُنشئ الافتراضي
  User({
    required this.id,
    required this.name,
    required this.email,
    required this.age,
    DateTime? createdAt,
    this.metadata,
  }) : createdAt = createdAt ?? DateTime.now();

  // مُنشئ التهيئة — من JSON
  User.fromJson(Map<String, dynamic> json)
      : id = json['id'] as String,
        name = json['name'] as String,
        email = json['email'] as String,
        age = json['age'] as int,
        createdAt = DateTime.parse(json['createdAt'] as String),
        metadata = json['metadata'] as Map<String, dynamic>?;

  // مُنشئ إعادة التوجيه — guest
  User.guest()
      : id = 'guest-${DateTime.now().millisecondsSinceEpoch}',
        name = 'Guest',
        email = 'guest@example.com',
        age = 0,
        createdAt = null,
        metadata = null;

  // مُنشئ المُصنّع — Singleton
  static User? _currentUser;
  factory User.current() {
    _currentUser ??= User.guest();
    return _currentUser!;
  }

  @override
  String toString() => 'User($id, $name, $age)';
}

void main() {
  final u1 = User(
    id: '001',
    name: 'Bob',
    email: 'bob@example.com',
    age: 25,
  );
  print(u1);

  final u2 = User.fromJson({
    'id': '002',
    'name': 'Alice',
    'email': 'alice@example.com',
    'age': 30,
    'createdAt': '2026-07-27T10:00:00Z',
  });
  print(u2);

  final u3 = User.guest();
  print(u3);

  final u4 = User.current();
  print(u4);
}
TEXT 📖 للعرض فقط
> **الإخراج:** 4 طرق لإنشاء User — من معاملات، من JSON، كضيف، Singleton.

5. الوراثة

(1) الوراثة الأساسية

DART
// فئة أساسية
class Animal {
  String name;
  int age;

  Animal(this.name, this.age);

  void eat() => print('$name is eating');
  void sleep() => print('$name is sleeping');
}

// فئة فرعية
class Dog extends Animal {
  String breed;

  // استدعاء مُنشئ الفئة الأساسية
  Dog(String name, int age, this.breed) : super(name, age);

  // طريقة جديدة
  void bark() => print('$name says: Woof!');

  // تجاوز الطريقة
  @override
  void eat() => print('$name (the dog) is eating kibble');
}

final dog = Dog('Rex', 5, 'Labrador');
dog.eat();     // 'Rex (the dog) is eating kibble'
dog.sleep();   // 'Rex is sleeping'
dog.bark();    // 'Rex says: Woof!'

(2) super في المُنشئات

DART
class Animal {
  String name;
  int age;

  // مُنشئ افتراضي
  Animal(this.name, this.age);

  // مُنشئ مسمى
  Animal.guest() : name = 'Guest', age = 0;
}

class Dog extends Animal {
  String breed;

  // استدعاء المُنشئ الافتراضي
  Dog(String name, int age, this.breed) : super(name, age);

  // استدعاء المُنشئ المسمى
  Dog.puppy(String name) : super.guest();

  // مع قائمة المعلمات
  Dog.adult() : super('Adult Dog', 5);
}

final d1 = Dog('Rex', 5, 'Labrador');
final d2 = Dog.puppy('Puppy');
final d3 = Dog.adult();

(3) الوراثة المتعددة المستويات

DART
class Animal {
  String name;
  Animal(this.name);
  void speak() => print('$name makes a sound');
}

class Dog extends Animal {
  Dog(String name) : super(name);
  @override
  void speak() => print('$name says: Woof!');
}

class Puppy extends Dog {
  Puppy(String name) : super(name);
  @override
  void speak() => print('$name (puppy) yips!');
}

final p = Puppy('Buddy');
p.speak();  // 'Buddy (puppy) yips!'

(4) تجاوز الطرق (Override)

DART
class Shape {
  double get area => 0.0;
  String get name => 'شكل';
}

class Circle extends Shape {
  final double radius;
  Circle(this.radius);
  @override
  double get area => 3.14159 * radius * radius;
  @override
  String get name => 'دائرة';
}

class Rectangle extends Shape {
  final double width, height;
  Rectangle(this.width, this.height);
  @override
  double get area => width * height;
  @override
  String get name => 'مستطيل';
}

void printArea(Shape shape) {
  print('${shape.name}: مساحة = ${shape.area}');
}

printArea(Circle(5));        // 'دائرة: مساحة = 78.5398'
printArea(Rectangle(4, 6));  // 'مستطيل: مساحة = 24.0'

(5) استدعاء super.xxx في الطريقة المُتجاوزة

DART
class Animal {
  String name;
  Animal(this.name);
  void describe() => print('أنا حيوان اسمي $name');
}

class Dog extends Animal {
  String breed;
  Dog(String name, this.breed) : super(name);

  @override
  void describe() {
    super.describe();  // استدعاء الفئة الأساسية
    print('أنا من سلالة $breed');
  }
}

final d = Dog('Rex', 'Labrador');
d.describe();
// أنا حيوان اسمي Rex
// أنا من سلالة Labrador

(6) لا يمكن تجاوز final methods

DART
class Base {
  final void cannotOverride() => print('لا يمكن تجاوزي');
}

class Derived extends Base {
  // @override
  // void cannotOverride() { }  // ❌ خطأ في وقت الترجمة
}

(7) final فئة — لا يمكن الوراثة

DART
final class ImmutableUser {
  final String name;
  final int age;
  ImmutableUser(this.name, this.age);
}

// class ExtendedUser extends ImmutableUser { }  // ❌ خطأ

(8) الوراثة مع Mixin

DART
mixin Swimmer {
  void swim() => print('يستطيع السباحة');
}

mixin Flyer {
  void fly() => print('يستطيع الطيران');
}

class Duck extends Animal with Swimmer, Flyer {
  Duck(String name) : super(name);
}

final d = Duck('Donald');
d.swim();  // 'يستطيع السباحة'
d.fly();   // 'يستطيع الطيران'

▶ مثال: نظام الفئات الحيوانية

DART
// فئة أساسية
class Animal {
  String name;
  int age;

  Animal(this.name, this.age);

  void eat() => print('$name is eating');
  void sleep() => print('$name is sleeping');

  String get info => '$name, $age years old';
}

// كلب
class Dog extends Animal {
  String breed;
  Dog(String name, int age, this.breed) : super(name, age);

  @override
  void eat() => print('$name (the dog) is eating kibble');

  void bark() => print('$name says: Woof!');
  void fetch() => print('$name fetches the ball');
}

// قطة
class Cat extends Animal {
  String color;
  Cat(String name, int age, this.color) : super(name, age);

  @override
  void eat() => print('$name (the cat) is eating fish');

  void meow() => print('$name says: Meow!');
  void purr() => print('$name is purring');
}

// طائر
class Bird extends Animal {
  double wingspan;
  Bird(String name, int age, this.wingspan) : super(name, age);

  @override
  void eat() => print('$name (the bird) is eating seeds');

  void fly() => print('$name is flying (wingspan: ${wingspan}cm)');
  void sing() => print('$name is singing');
}

void describe(Animal animal) {
  print(animal.info);
  animal.eat();
  animal.sleep();

  if (animal is Dog) {
    animal.bark();
    animal.fetch();
  } else if (animal is Cat) {
    animal.meow();
    animal.purr();
  } else if (animal is Bird) {
    animal.fly();
    animal.sing();
  }
  print('---');
}

void main() {
  describe(Dog('Rex', 5, 'Labrador'));
  describe(Cat('Whiskers', 3, 'orange'));
  describe(Bird('Tweety', 1, 15.0));
}
TEXT 📖 للعرض فقط
> **الإخراج:** نظام OOP كامل — 3 فئات فرعية مع طرق فريدة، والتحقق من النوع في وقت التشغيل باستخدام `is`.

6. الفئات المجردة (Abstract Classes)

(1) ما هي الفئة المجردة؟

DART
// فئة مجردة — لا يمكن إنشاء مثيل منها
abstract class Shape {
  // طريقة مجردة — يجب تنفيذها في الفئة الفرعية
  double get area;
  double get perimeter;

  // طريقة ملموسة — لها تطبيق
  void describe() => print('أنا شكل بمساحة $area ومحيط $perimeter');
}

class Circle extends Shape {
  final double radius;
  Circle(this.radius);
  @override
  double get area => 3.14159 * radius * radius;
  @override
  double get perimeter => 2 * 3.14159 * radius;
}

class Rectangle extends Shape {
  final double width, height;
  Rectangle(this.width, this.height);
  @override
  double get area => width * height;
  @override
  double get perimeter => 2 * (width + height);
}

// final s = Shape();  // ❌ خطأ — لا يمكن إنشاء مثيل من فئة مجردة
final s = Circle(5);
s.describe();  // 'أنا شكل بمساحة 78.54 ومحيط 31.42'

(2) مُنشئ في الفئة المجردة

DART
abstract class Animal {
  final String name;
  Animal(this.name);  // مُنشئ مع معامل

  // طريقة مجردة
  void speak();

  // طريقة ملموسة
  void describe() => print('أنا $name');
}

class Dog extends Animal {
  Dog(String name) : super(name);

  @override
  void speak() => print('$name says: Woof!');
}

final d = Dog('Rex');
d.describe();
d.speak();

(3) abstract طريقة

DART
abstract class Database {
  // طريقة مجردة — لا يوجد تطبيق
  void connect();
  void query(String sql);
  void close();
}

class MySQLDatabase extends Database {
  @override
  void connect() => print('MySQL متصل');

  @override
  void query(String sql) => print('MySQL: $sql');

  @override
  void close() => print('MySQL مغلق');
}

class PostgresDatabase extends Database {
  @override
  void connect() => print('Postgres متصل');

  @override
  void query(String sql) => print('Postgres: $sql');

  @override
  void close() => print('Postgres مغلق');
}

void useDb(Database db) {
  db.connect();
  db.query('SELECT * FROM users');
  db.close();
}

useDb(MySQLDatabase());
useDb(PostgresDatabase());

(4) الفئة المجردة مقابل الواجهة

DART
// فئة مجردة — يمكن أن تحتوي على تطبيقات
abstract class Animal {
  void speak() => print('...');  // تطبيق افتراضي
  void move();  // طريقة مجردة
}

// واجهة — كل الطرق مجردة (Dart 3)
abstract interface class Swimmable {
  void swim();  // كل الطرق مجردة
}

▶ مثال: نظام قاعدة البيانات

DART
// واجهة قاعدة البيانات
abstract class Database {
  void connect();
  void disconnect();
  List<Map<String, dynamic>> query(String sql);
  void execute(String sql);
}

class MySQLDatabase implements Database {
  String host;
  int port;
  String? connection;

  MySQLDatabase(this.host, this.port);

  @override
  void connect() {
    connection = 'mysql://$host:$port';
    print('MySQL متصل: $connection');
  }

  @override
  void disconnect() {
    connection = null;
    print('MySQL مغلق');
  }

  @override
  List<Map<String, dynamic>> query(String sql) {
    print('MySQL query: $sql');
    return [];
  }

  @override
  void execute(String sql) {
    print('MySQL execute: $sql');
  }
}

void useDb(Database db) {
  db.connect();
  db.query('SELECT * FROM users');
  db.execute('UPDATE users SET name = "Bob"');
  db.disconnect();
}

void main() {
  useDb(MySQLDatabase('localhost', 3306));
}
TEXT 📖 للعرض فقط
> **الإخراج:** نظام قاعدة البيانات — واجهة موحدة، تطبيقات مختلفة.

7. الواجهات الضمنية (Implicit Interfaces)

(1) كل فئة هي واجهة ضمنية

DART
// في Dart، كل فئة هي واجهة ضمنية
class Dog {
  void bark() => print('Woof!');
  void eat() => print('Eating');
}

class Cat {
  void bark() => print('Meow!');
  void eat() => print('Eating');
}

// يقبل أي فئة بها bark() و eat()
void makeSound(Dog dog) {
  dog.bark();
  dog.eat();
}

// ❌ لا يمكن تمرير Cat مباشرة (نظام نوع صارم)
// makeSound(Cat());  // خطأ

// ✅ مع implements
class CatAdapter implements Dog {
  @override
  void bark() => print('Meow!');

  @override
  void eat() => print('Eating');
}

(2) implements بدلاً من extends

DART
// واجهة (ضمنية)
abstract class Animal {
  void speak();
}

// فئة تنفذ الواجهة الضمنية
class Robot implements Animal {
  @override
  void speak() => print('Beep boop');
}

final r = Robot();
final a = r as Animal;  // تحويل آمن
a.speak();  // 'Beep boop'

(3) implements مع واجهات Dart 3

DART
// واجهة صريحة في Dart 3
abstract interface class Drawable {
  void draw();
}

abstract interface class Resizable {
  void resize(double factor);
}

// فئة تنفذ واجهات متعددة
class Circle implements Drawable, Resizable {
  double radius = 1.0;

  @override
  void draw() => print('رسم دائرة بنصف قطر $radius');

  @override
  void resize(double factor) {
    radius *= factor;
    print('دائرة جديدة: نصف قطر $radius');
  }
}

final c = Circle();
c.draw();
c.resize(2.0);

(4) extends + implements معًا

DART
class Animal {
  String name;
  Animal(this.name);
  void speak() => print('$name: ...');
}

abstract interface class Swimmable {
  void swim();
}

// ✅ extends فئة، implements واجهة
class Duck extends Animal implements Swimmable {
  Duck(String name) : super(name);

  @override
  void speak() => print('$name: Quack!');

  @override
  void swim() => print('$name is swimming');
}

(5) extends مع ميكسن

DART
mixin Loggable {
  void log(String message) => print('[LOG] $message');
}

class Service with Loggable {
  void doWork() {
    log('Doing work');
  }
}

final s = Service();
s.doWork();
// [LOG] Doing work

(6) فئة مختومة (صنف مختوم) - Dart 3

DART
// sealed class — يمكن تمديدها فقط في نفس المكتبة
sealed class Result<T> {}
class Success<T> extends Result<T> {
  final T value;
  Success(this.value);
}
class Failure<T> extends Result<T> {
  final String error;
  Failure(this.error);
}

// switch التعبيرية يجب أن تكون شاملة
String handle<T>(Result<T> result) => switch (result) {
  Success(:final value) => 'Success: $value',
  Failure(:final error) => 'Error: $error',
};

▶ مثال: نظام الواجهة المتعددة

DART
// عدة واجهات
abstract interface class Drawable {
  void draw();
}

abstract interface class Movable {
  void move(int x, int y);
}

abstract interface class Resizable {
  void resize(double factor);
}

abstract interface class Serializable {
  String serialize();
}

// فئة تنفذ 4 واجهات
class Square implements Drawable, Movable, Resizable, Serializable {
  double x, y, size;

  Square(this.x, this.y, this.size);

  @override
  void draw() => print('رسم مربع في ($x، $y) بحجم $size');

  @override
  void move(int dx, int dy) {
    x += dx;
    y += dy;
    print('نقل إلى ($x، $y)');
  }

  @override
  void resize(double factor) {
    size *= factor;
    print('حجم جديد: $size');
  }

  @override
  String serialize() => '{"x": $x, "y": $y, "size": $size}';
}

void main() {
  final s = Square(0, 0, 10);
  s.draw();
  s.move(5, 5);
  s.resize(2.0);
  print(s.serialize());
}
TEXT 📖 للعرض فقط
> **الإخراج:** Square مع 4 واجهات — رسم، نقل، تحجيم، تسلسل.

8. Mixin

(1) ما هو Mixin؟

Mixin هو طريقة لمشاركة الكود عبر فئات متعددة دون وراثة.

DART
// Mixin — مجموعة من الخصائص والطُرق
mixin Swimmer {
  void swim() => print('يستطيع السباحة');
}

mixin Flyer {
  void fly() => print('يستطيع الطيران');
}

mixin Walker {
  void walk() => print('يستطيع المشي');
}

// فئة تستخدم Mixins
class Duck extends Animal with Swimmer, Flyer, Walker {
  Duck(String name) : super(name);
  @override
  void speak() => print('$name: Quack!');
}

class Fish extends Animal with Swimmer {
  Fish(String name) : super(name);
  @override
  void speak() => print('$name: Blub');
}

class Dog extends Animal with Walker {
  Dog(String name) : super(name);
  @override
  void speak() => print('$name: Woof!');
}

(2) Mixin مع خصائص

DART
mixin Timestamp {
  DateTime createdAt = DateTime.now();
  DateTime updatedAt = DateTime.now();

  void touch() {
    updatedAt = DateTime.now();
  }
}

class User with Timestamp {
  String name;
  User(this.name);
}

final u = User('Bob');
print('Created: ${u.createdAt}');
u.touch();
print('Updated: ${u.updatedAt}');

(3) Mixin كـ abstract

DART
abstract mixin class Comparable<T> {
  int compareTo(T other);
}

class Version implements Comparable<Version> {
  final int major, minor, patch;
  Version(this.major, this.minor, this.patch);

  @override
  int compareTo(Version other) {
    if (major != other.major) return major.compareTo(other.major);
    if (minor != other.minor) return minor.compareTo(other.minor);
    return patch.compareTo(other.patch);
  }
}

final v1 = Version(1, 0, 0);
final v2 = Version(1, 2, 0);
print(v1.compareTo(v2));  // -1

(4) Mixin on — يقيد الاستخدام

DART
// Mixin يمكن استخدامه فقط على فئات ترث من Animal
mixin Swimmer on Animal {
  void swim() => print('$name is swimming');
}

class Duck extends Animal with Swimmer {
  Duck(String name) : super(name);
}
// class Plant with Swimmer { }  // ❌ خطأ — Plant لا يرث من Animal

(5) Mixin ترتيب — linearization

DART
mixin A {
  String get name => 'A';
}
mixin B {
  String get name => 'B';
}

class C with A, B {}

final c = C();
print(c.name);  // 'B' (B بعد A)

▶ مثال: نظام Mixin للحيوانات

DART
abstract class Animal {
  String name;
  Animal(this.name);
  void speak() => print('$name: ...');
}

mixin Swimmer {
  void swim() => print('$name is swimming');
}

mixin Flyer {
  void fly() => print('$name is flying');
}

mixin Walker {
  void walk() => print('$name is walking');
}

mixin Hunter {
  void hunt() => print('$name is hunting');
}

class Duck extends Animal with Swimmer, Flyer, Walker {
  Duck(String name) : super(name);
  @override
  void speak() => print('$name: Quack!');
}

class Eagle extends Animal with Flyer, Hunter {
  Eagle(String name) : super(name);
  @override
  void speak() => print('$name: Screech!');
}

class Salmon extends Animal with Swimmer {
  Salmon(String name) : super(name);
  @override
  void speak() => print('$name: Splash');
}

void describe(Animal animal) {
  print('${animal.name}:');
  animal.speak();
  if (animal is Swimmer) animal.swim();
  if (animal is Flyer) animal.fly();
  if (animal is Walker) animal.walk();
  if (animal is Hunter) animal.hunt();
  print('---');
}

void main() {
  describe(Duck('Donald'));
  describe(Eagle('Aquila'));
  describe(Salmon('Finn'));
}
TEXT 📖 للعرض فقط
> **الإخراج:** نظام Mixin — كل حيوان يحصل على القدرات المناسبة (Duck يسبح+يطير+يمشي، Eagle يطير+يصطاد، Salmon يسبح فقط).

9. المُهيِّئات (Initializers)

(1) قائمة المُهيِّئات

DART
class Point {
  final double x, y;

  // قائمة المُهيِّئات — تنفيذ قبل جسم المُنشئ
  Point(this.x, this.y)
      : assert(x >= 0, 'x must be non-negative'),
        assert(y >= 0, 'y must be non-negative');

  // تهيئة من JSON
  Point.fromJson(Map<String, dynamic> json)
      : x = json['x'] as double,
        y = json['y'] as double;

  // تهيئة معقدة
  Point.fromPolar(double radius, double angle)
      : x = radius * Math.cos(angle),
        y = radius * Math.sin(angle);
}

(2) assert في المُهيِّئات

DART
class User {
  final int age;

  User(this.age) : assert(age >= 0, 'Age must be non-negative');

  // assert يعمل فقط في وضع التطوير
  // في الإنتاج، تتم إزالته
}

User(25);  // ✅
User(-5);  // ❌ AssertionError (في وضع التطوير)

(3) super في المُهيِّئات

DART
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  String breed;
  Dog(String name, this.breed) : super(name);
}

(4) إعادة التوجيه

DART
class User {
  final String name;
  User(this.name);
  User.guest() : this('Guest');  // إعادة توجيه
}

10. أنماط OOP الشائعة

(1) getter فقط (immutable كائن)

DART
class ImmutableUser {
  final String _name;
  final int _age;

  ImmutableUser(this._name, this._age);

  String get name => _name;
  int get age => _age;

  @override
  String toString() => 'ImmutableUser($_name, $_age)';
}

final u = ImmutableUser('Bob', 25);
print(u.name);  // 'Bob'
print(u.age);   // 25
// u.name = 'Alice';  // ❌ لا يمكن التعيين (لا setter)

(2) Builder pattern

DART
class HttpRequest {
  final String url;
  final String method;
  final Map<String, String> headers;
  final String? body;
  final int timeout;

  HttpRequest._({
    required this.url,
    required this.method,
    required this.headers,
    required this.body,
    required this.timeout,
  });

  static Builder builder(String url) => Builder._(url);
}

class Builder {
  String _method = 'GET';
  Map<String, String> _headers = {};
  String? _body;
  int _timeout = 30;

  Builder._(this._url);
  String _url;

  Builder method(String m) { _method = m; return this; }
  Builder header(String k, String v) { _headers[k] = v; return this; }
  Builder body(String b) { _body = b; return this; }
  Builder timeout(int t) { _timeout = t; return this; }

  HttpRequest build() => HttpRequest._(
    url: _url, method: _method, headers: _headers, body: _body, timeout: _timeout,
  );
}

// الاستخدام
final req = HttpRequest.builder('https://api.example.com')
  ..method('POST')
  ..header('Content-Type', 'application/json')
  ..body('{"name": "Bob"}')
  ..timeout(60)
  ..build();

(3) Singleton

DART
class DatabaseConnection {
  static final DatabaseConnection _instance = DatabaseConnection._internal();
  factory DatabaseConnection() => _instance;

  DatabaseConnection._internal();

  String connection = '';

  void connect() {
    connection = 'postgresql://localhost';
    print('Connected: $connection');
  }
}

final db1 = DatabaseConnection();
final db2 = DatabaseConnection();
print(identical(db1, db2));  // true (Singleton)

(4) Repository pattern

DART
// واجهة
abstract class UserRepository {
  Future<User?> findById(String id);
  Future<List<User>> findAll();
  Future<void> save(User user);
  Future<void> delete(String id);
}

// تنفيذ في الذاكرة
class InMemoryUserRepository implements UserRepository {
  final Map<String, User> _users = {};

  @override
  Future<User?> findById(String id) async => _users[id];

  @override
  Future<List<User>> findAll() async => _users.values.toList();

  @override
  Future<void> save(User user) async {
    _users[user.id] = user;
  }

  @override
  Future<void> delete(String id) async {
    _users.remove(id);
  }
}

// تنفيذ API
class ApiUserRepository implements UserRepository {
  final String baseUrl;
  ApiUserRepository(this.baseUrl);

  @override
  Future<User?> findById(String id) async {
    // طلب API
    return null;
  }

  // ... تطبيقات أخرى
}

(5) Factory طريقة

DART
abstract class Document {
  void open();
  void save();
  void close();
}

abstract class DocumentFactory {
  Document createDocument();
}

class PdfDocument implements Document {
  @override
  void open() => print('فتح PDF');
  @override
  void save() => print('حفظ PDF');
  @override
  void close() => print('إغلاق PDF');
}

class PdfDocumentFactory implements DocumentFactory {
  @override
  PdfDocument createDocument() => PdfDocument();
}

▶ مثال: نظام OOP شامل

DART
// واجهة المستخدم
abstract class User {
  String get id;
  String get name;
  String get email;

  String getInfo();
}

// عدة تطبيقات
class RealUser implements User {
  @override
  final String id;
  @override
  final String name;
  @override
  final String email;
  final DateTime createdAt;

  RealUser(this.id, this.name, this.email) : createdAt = DateTime.now();

  @override
  String getInfo() => 'User $name ($email)';
}

class GuestUser implements User {
  @override
  String get id => 'guest';
  @override
  String get name => 'Guest';
  @override
  String get email => 'guest@example.com';

  @override
  String getInfo() => 'Guest User';
}

// Factory
class UserFactory {
  static User create({
    required String type,
    String? id,
    String? name,
    String? email,
  }) {
    switch (type) {
      case 'real':
        if (id == null || name == null || email == null) {
          throw ArgumentError('Real user needs id, name, email');
        }
        return RealUser(id, name, email);
      case 'guest':
        return GuestUser();
      default:
        throw ArgumentError('Unknown user type: $type');
    }
  }
}

void main() {
  final u1 = UserFactory.create(type: 'real', id: '001', name: 'Bob', email: 'bob@example.com');
  final u2 = UserFactory.create(type: 'guest');

  print(u1.getInfo());  // 'User Bob (bob@example.com)'
  print(u2.getInfo());  // 'Guest User'
}
TEXT 📖 للعرض فقط
> **الإخراج:** نظام OOP — واجهة، تطبيقات متعددة، factory لإنشاء.

11. ملخص نقاط المعرفة الأساسية لهذا الدرس

# المفهوم المستوى الأهمية
1 إعلان الفئة والخصائص والطُرق مبتدئ ⭐⭐⭐⭐⭐
2 5 أنواع من المُنشئات مبتدئ ⭐⭐⭐⭐⭐
3 الوراثة و super مبتدئ ⭐⭐⭐⭐⭐
4 تجاوز الطريقة @override متوسط ⭐⭐⭐⭐⭐
5 الفئات المجردة صنف مجرد متوسط ⭐⭐⭐⭐
6 الواجهات الضمنية implements متوسط ⭐⭐⭐⭐
7 Mixin متوسط ⭐⭐⭐⭐
8 صنف مختوم (Dart 3) متوسط ⭐⭐⭐⭐⭐
9 abstract interface فئة (Dart 3) متوسط ⭐⭐⭐
10 Constructor initializer list متوسط ⭐⭐⭐⭐

❓ أسئلة شائعة

س ما الفرق بين extends و implements؟
ج extends: وراثة الفئة الأصلية، تحصل على خصائصها وطرقها. implements: تنفيذ الواجهة، يجب عليك إعادة تنفيذ كل الطرق. استخدم extends عندما تريد إعادة استخدام الكود. استخدم implements عندما تريد تطبيق نفس الواجهة بطرق مختلفة.
س متى تستخدم صنف مجرد و abstract interface فئة؟
ج صنف مجرد: يمكن أن تحتوي على تطبيقات افتراضية، لها مُنشئ. abstract interface فئة (Dart 3): كل الطرق مجردة (لا تطبيقات)، لا يمكن أن يكون لها حقول. استخدم صنف مجرد عندما تريد مشاركة الكود. استخدم abstract interface فئة عندما تريد تعريف API فقط.
س صنف مختوم و صنف مجرد الفرق؟
ج صنف مختوم (Dart 3): يمكن تمديدها فقط في نفس المكتبة، تستخدم مع switch التعبيرية لتحقيق فحص شامل. صنف مجرد: يمكن تمديدها في أي مكان. sealed أكثر صرامة، تُستخدم لمنع الفئات الفرعية غير المصرح بها.
س لماذا final فئة غير قابل للوراثة؟
ج final فئة (Dart 3): لا يمكن لأي فئة أن ترث منها. هذا تحسين أداء (المترجم يعرف أن الفئة لا تحتوي على فئات فرعية) وأمان (يمنع التعديل من قبل الآخرين). استخدم final فئة عندما تريد التأكد من أن الفئة لن يتم تمديدها.
س ما الفرق بين ميكسن و صنف مجرد؟
ج ميكسن: مجموعة من الخصائص والطرق يمكن خلطها في فئات متعددة. صنف مجرد: فئة كاملة (مع مُنشئ، خصائص، طرق) لا يمكن إنشاء مثيل منها. استخدم ميكسن لمشاركة الكود عبر فئات متعددة. استخدم صنف مجرد لتعريف واجهة مع تطبيقات افتراضية.
س صنف مختوم vs enum — متى تستخدم كل واحد؟
ج enum: مجموعة ثابتة من القيم (مثل red, green, blue). صنف مختوم: مجموعة من الفئات الفرعية (مثل Success, Failure). صنف مختوم أكثر مرونة، يمكن أن تحمل بيانات مختلفة لكل حالة.

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ⭐): أنشئ مشروع bank_account، واكتب فئة BankAccount مع خصائص (accountNumber, owner, balance) و 3 مُنشئات (افتراضي، مع معاملات، من JSON) و 4 طرق (deposit, withdraw, getInfo, transferTo). أنشئ bin/main.dart يوضح السيناريوهات: ① حساب جديد بـ 0 رصيد ② إيداع 1000 ③ سحب 500 ④ نقل 200 إلى حساب آخر. استخدم assert في withdraw و transferTo للتحقق من كفاية الرصيد. تلميح: استخدم String padLeft لتنسيق accountNumber.
  2. متوسط (الصعوبة ⭐⭐): أنشئ مشروع shape_hierarchy، يحتوي على 4 فئات: Shape (abstract) / Circle (radius) / Rectangle (width, height) / Triangle (base, height). كل فئة فرعية تنفذ: area / perimeter / describe. أضف Mixin Drawable و Rotatable يُستخدمان في 2 فئات مختلفة. اختبر 5 أشكال (3 دوائر، 2 مستطيلات). استخدم صنف مختوم + switch expressions للمعالجة متعددة الأشكال. تلميح: استخدم late final للحقول المحسوبة مثل area.
  3. تحدٍّ (الصعوبة ⭐⭐⭐): أنشئ مشروع payment_system، يحتوي على 4 فئات: Payment (abstract) / CreditCardPayment / BankTransferPayment / CryptoPayment. كل فئة لها process(amount) و fee و validate(). استخدم صنف مختوم + switch expressions لتنفيذ processPayments(List<Payment> payments) التي تعالج جميع المدفوعات. أنشئ 3 واجهات: Refundable (للمبالغ المستردة) و Traceable (لتتبع المعاملات) و Notifiable (لإرسال الإشعارات). أنشئ OrderService يستخدم DI (حقن التبعية) لتلقي قائمة طرق الدفع. اختبر مع 10 مدفوعات مختلطة. تلميح: استخدم Provider نمط أو DI اليدوي.

← السابق: دوال Dart | التالي: المجموعات في Dart →

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%