OOP Static Variable And Static Functions

✅ أولاً: تعريف المتغير الثابت static

في لغة Dart، عند استخدام الكلمة المفتاحية static مع متغير داخل كلاس (class)، فهذا يعني أن هذا المتغير:

  • مشترك بين كل الكائنات (objects) من نفس الكلاس.
  • لا يتم نسخه عند إنشاء كائن جديد.
  • يتبع الكلاس نفسه، وليس الكائنات.
✅ الشكل العام للمتغير الثابت
class ClassName {
  static DataType variableName = value;
}
Dart
✅ مثال بسيط وشرح مفصل:
class Counter {
  static int count = 0;

  void increment() {
    count++;
  }

  void showCount() {
    print("Count = $count");
  }
}

void main() {
  Counter c1 = Counter();
  Counter c2 = Counter();

  c1.increment();
  c2.increment();

  c1.showCount(); // Count = 2
  c2.showCount(); // Count = 2
}
Dart
✅ شرح المثال:
  1. أنشأنا class باسم Counter.
  2. فيه متغير count معرف كـ static int يعني مشترك بين كل الكائنات.
  3. أنشأنا كائنين c1 و c2.
  4. كل واحد استدعى increment()، وهذا زاد القيمة من نفس المتغير count.
  5. عند الطباعة من c1 أو c2، النتيجة نفسها: 2، لأنهم يشتركون في نفس المتغير.
✅ الفوائد من استخدام static
الفائدةالتوضيح
💡 التوفير في الذاكرةبدل إنشاء نسخة من المتغير مع كل كائن، تبقى نسخة واحدة فقط.
🔁 المشاركة بين الكائناتالكل يستخدم نفس المتغير – مثالي للتعداد أو التخزين العام.
🧱 إمكانية الوصول بدون إنشاء كائنيمكنك الوصول للمتغير باستخدام الكلاس نفسه، مثل Counter.count.
✅ الوصول إلى المتغير الثابت بدون كائن:
void main() {
  print(Counter.count); // 2
}
Dart
✅ ملاحظة مهمة:
  • لا يمكنك استخدام this داخل متغير static أو دالة static.
  • لأن this تشير إلى كائن (object)، والمتغيرات الثابتة لا تنتمي للكائنات بل للكلاس نفسه.
✅ استخدامات عملية للمتغير static
الحالةالشرح
🔢 عدّاد عامعدّ عدد الكائنات التي تم إنشاؤها من الكلاس.
⚙️ إعدادات أو إعداد ثابتقيمة ثابتة مشتركة مثل API Key أو إعداد عام.
🧾 Cache أو تخزين مؤقتتخزين بيانات يمكن لجميع الكائنات الوصول إليها.
🧪 في الاختباراتاستخدام قيم ثابتة يتم التحقق منها في كل اختبار.
✅ مثال عملي 2: عدّاد الكائنات
class User {
  static int totalUsers = 0;

  String name;

  User(this.name) {
    totalUsers++;
  }

  void showUser() {
    print("User: $name");
  }
}

void main() {
  User u1 = User("Ali");
  User u2 = User("Omar");

  print("Total users: ${User.totalUsers}"); // Total users: 2
}
Dart
✅ دمج static مع const أو final
  • يمكنك استخدام static const للثوابت العامة.
  • مثال:
class Settings {
  static const String appName = "My App";
  static const int maxUsers = 100;
}
Dart
✅ الفرق بين static و instance variable
المقارنةstatic variableinstance variable
ملك لمن؟الكلاسالكائن
عدد النسخنسخة واحدةنسخة لكل كائن
الاستخدامعام مشتركخاص بالكائن
الوصولClassName.variableobject.variable
✅ خلاصة شاملة:
  • static تعني أن المتغير (أو الدالة) ينتمي للكلاس وليس للكائن.
  • مثالي لمشاركة البيانات بين الكائنات.
  • يوفر ذاكرة ويمنع التكرار.
  • لا يُستخدم فيه this.
  • يمكن الوصول إليه مباشرة باستخدام اسم الكلاس.
✅ أولاً: ما هي الدالة الثابتة static method؟

هي دالة تابعة للكلاس نفسه، وليست تابعة لأي كائن (object) منه.

أي يمكننا استدعاؤها بدون إنشاء كائن من الكلاس، لأنها لا تعتمد على البيانات الخاصة بأي كائن (لا تستخدم this).

✅ الشكل العام:
class ClassName {
  static returnType methodName(parameters) {
    // تنفيذ الدالة
  }
}
Dart
✅ مثال بسيط:
class MathHelper {
  static int square(int number) {
    return number * number;
  }
}

void main() {
  int result = MathHelper.square(5);
  print(result); // 25
}
Dart
✅ شرح المثال:
  1. أنشأنا كلاس اسمه MathHelper.
  2. داخله دالة square() تم تعريفها باستخدام static.
  3. قمنا باستدعاء الدالة مباشرة من الكلاس: MathHelper.square(5) بدون إنشاء كائن.
  4. النتيجة هي 25 لأن 5 × 5 = 25.
✅ ملاحظات مهمة:
ملاحظةشرح
❌ لا تستخدم thisلأن الدالة لا تعمل على كائن بل على الكلاس مباشرة.
✅ يمكن استخدامها بدون new أو إنشاء كائنفقط باسم الكلاس.
❌ لا تصل للخصائص غير staticالدالة static لا يمكنها الوصول للمتغيرات أو الدوال العادية داخل الكلاس.
✅ مثال متقدم أكثر: آلة حاسبة
class Calculator {
  static double add(double a, double b) => a + b;
  static double subtract(double a, double b) => a - b;
  static double multiply(double a, double b) => a * b;
  static double divide(double a, double b) {
    if (b == 0) {
      print("لا يمكن القسمة على صفر");
      return 0;
    }
    return a / b;
  }
}

void main() {
  print(Calculator.add(10, 5));      // 15
  print(Calculator.subtract(10, 5)); // 5
  print(Calculator.multiply(10, 5)); // 50
  print(Calculator.divide(10, 0));   // لا يمكن القسمة على صفر → 0
}
Dart
✅ لماذا استخدمنا static هنا؟

لأن هذه العمليات لا تعتمد على بيانات داخل الكلاس، فهي مجرد وظائف عامة، وليس هناك حاجة لإنشاء كائن لتنفيذها.

✅ مثال عملي مهم: توليد ID تلقائي
class IDGenerator {
  static int _currentId = 0;

  static int generateId() {
    _currentId++;
    return _currentId;
  }
}

void main() {
  print(IDGenerator.generateId()); // 1
  print(IDGenerator.generateId()); // 2
  print(IDGenerator.generateId()); // 3
}
Dart
✅ شرح:
  • كل مرة تستدعي generateId يتم زيادة المتغير _currentId.
  • بما أنه static، فإن جميع الاستدعاءات تشترك في نفس القيمة.
  • مثال ممتاز لتوليد معرفات متسلسلة دون الحاجة لإنشاء كائن.
✅ حالات الاستخدام الشائعة للدوال الثابتة
الحالةالوصف
🔢 أدوات المساعدة (Utility Functions)مثل التحقق، التحويلات، الحسابات الرياضية.
🔁 العمليات العامةمثل إنشاء ID، أو تهيئة إعداد.
🧱 إعدادات الكلاسدوال تتعامل مع البيانات static داخل الكلاس.
📦 أدوات ثابتة لا تتغيرمثل AppConfig.getApiUrl() أو Validator.isEmail().
✅ دمج static method مع static variable
class Counter {
  static int _count = 0;

  static void increment() {
    _count++;
  }

  static void show() {
    print("Count = $_count");
  }
}

void main() {
  Counter.increment();
  Counter.increment();
  Counter.show(); // Count = 2
}
Dart
✅ الفرق بين الدوال العادية و static
المقارنةدالة عادية (غير static)دالة static
تتطلب كائن؟نعملا
تستخدم this؟نعملا
تصل للخصائص العادية؟نعملا
تستخدم مع خصائص ودوال static؟لانعم
✅ خلاصة شاملة:
  • static methods هي دوال تنتمي للكلاس.
  • تُستخدم بدون إنشاء كائن.
  • لا يمكنها استخدام this أو الوصول للخصائص غير الثابتة.
  • مثالية للأدوات الحسابية، التحقق، التهيئة، والإعدادات العامة.
  • تجعل الكود منظمًا وقابلًا لإعادة الاستخدام.