OOP Factory Constructor In Dart

🏭 ما هو Factory Constructor؟
✅ التعريف:

Factory Constructor هو نوع خاص من الـ Constructor يُستخدم عندما تريد التحكم في إنشاء الكائن (object)، بدلًا من إنشائه مباشرة دائمًا.

يعني:
بدل ما new تنشئ كل مرة كائن جديد، تقدر تقول:

“لا، إذا كان هذا الكائن موجود سابقًا، رجعه لي”
أو “اعمل فحص قبل إنشاء الكائن”
أو “رجع كائن مختلف تمامًا!”

✅ متى نستخدم factory؟
السببالتوضيح
✅ عند إعادة استخدام كائن موجود (Singleton مثلاً)ما تنشئ كائن جديد
✅ عند تنفيذ منطق قبل الإنشاء (validation أو parsing)فحص القيم أولاً
✅ عند إرجاع كائن من نوع فرعي (subclass)ترجع كائن مختلف
✅ عند إرجاع قيمة غير تقليديةترجع null أو شيء مخصص
✅ الشكل العام:
class ClassName {
  factory ClassName() {
    // منطق الإنشاء المخصص
    return ...;
  }
}
Dart
✅ مثال 1: فحص قبل الإنشاء
class User {
  final String name;

  User._internal(this.name); // private constructor

  factory User(String name) {
    if (name.isEmpty) {
      throw Exception("الاسم لا يمكن أن يكون فارغًا");
    }
    return User._internal(name);
  }
}

void main() {
  var user = User("Ali"); // ✅ سليم
  // var user2 = User(""); ❌ سيرمي Exception
}
Dart
✅ الشرح:
  • استخدمنا factory لفحص الاسم قبل إنشاء الكائن.
  • إذا الاسم فاضي، نرمي Exception.
  • واستخدمنا constructor داخلي _internal ليكون خاص ولا يُستخدم من الخارج.

✅ مثال 2: Singleton (كائن واحد فقط)
class Logger {
  static final Logger _instance = Logger._internal();

  Logger._internal(); // private constructor

  factory Logger() {
    return _instance;
  }

  void log(String message) {
    print("LOG: $message");
  }
}

void main() {
  var l1 = Logger();
  var l2 = Logger();

  print(identical(l1, l2)); // true ✅ نفس الكائن
}
Dart
✅ الشرح:
  • كل استدعاء لـ Logger() يرجع نفس النسخة الوحيدة.
  • استخدمنا factory لتحقيق نمط Singleton.
✅ مثال 3: تحويل JSON إلى كائن
class Product {
  final String name;
  final double price;

  Product(this.name, this.price);

  factory Product.fromJson(Map<String, dynamic> json) {
    return Product(json['name'], json['price']);
  }
}

void main() {
  var json = {'name': 'Keyboard', 'price': 199.99};
  var product = Product.fromJson(json);

  print(product.name);  // Keyboard
}
Dart
✅ الشرح:
  • استخدمنا factory لتحويل JSON إلى كائن Product.
  • مثالي للتعامل مع APIs.
🆚 الفرق بين factory و constructor العادي
المقارنةconstructor العاديfactory constructor
ينشئ كائن جديد دائمًا؟✅ نعم❌ لا (اختياري)
يرجع نفس الكلاس فقط؟✅ نعم❌ ممكن يرجع subclass أو null
يمكنه تنفيذ منطق قبل الإنشاء؟❌ لا✅ نعم
يمكنه إرجاع كائن موجود؟❌ لا✅ نعم
هل يمكن استخدام return بداخله؟❌ لا✅ نعم
✅ متى أستخدم factory بدلاً من constructor عادي؟
الحالةاستخدم factory
تريد تنفيذ شرط أو فحص
تريد التحكم في منطق الإنشاء
تريد cache أو singleton
تريد إرجاع نوع مختلف
تريد parsing من JSON
✅ مثال 4: إرجاع نوع مختلف (SubClass)
abstract class Shape {
  void draw();
}

class Circle extends Shape {
  @override
  void draw() => print("رسم دائرة");
}

class Square extends Shape {
  @override
  void draw() => print("رسم مربع");
}

class ShapeFactory {
  factory ShapeFactory(String type) {
    if (type == "circle") return Circle();
    if (type == "square") return Square();
    throw Exception("شكل غير معروف");
  }
}

void main() {
  Shape s1 = ShapeFactory("circle");
  s1.draw(); // رسم دائرة
}
Dart
💡 خلاصة شاملة:
النقطةالتوضيح
factory constructorيعطيك مرونة عالية في إنشاء الكائنات
يمكنه إرجاع كائن جديد أو موجود
يمكنه إرجاع نوع مختلف أو null
مناسب لـ Singleton / JSON / فحص القيم
لا يستخدم this لإنشاء الكائن مباشرة❌ بل يستخدم return