المنشئات المصنعية
جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 14 من 110.
يُعد منشئ المصنع (factory constructor) منشئاً خاصاً لا يقوم دائماً بإنشاء مثيل جديد. وعلى عكس المنشئات العادية، يمكن لمنشئ المصنع إرجاع مثيل موجود بالفعل، أو نوع فرعي، أو حتى null (إذا كان يقبل القيمة null). يتم التصريح عنه باستخدام الكلمة المفتاحية factory.
class Logger {
static final Logger _instance = Logger._internal();
// منشئ مسمى خاص
Logger._internal();
// منشئ مصنع
factory Logger() {
return _instance;
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueفي هذا المثال، يعيد منشئ المصنع (factory constructor) دائماً نفس المثيل. بغض النظر عن عدد المرات التي تستدعي فيها Logger()، ستحصل على الكائن المتطابق نفسه. يُستخدم هذا النمط بشكل شائع لتنفيذ الـ singletons.
تختلف منشئات المصنع (Factory constructors) عن المنشئات العادية بطريقة أساسية: فهي لا تملك حق الوصول إلى this لأنها قد لا تنشئ مثيلاً جديداً على الإطلاق. بدلاً من ذلك، يجب عليها إرجاع كائن بشكل صريح:
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }تعد منشئات المصنع (Factory constructors) مفيدة عندما تحتاج إلى التحكم في عملية إنشاء الكائنات، مثل إرجاع الكائنات المخزنة مؤقتًا، أو تنفيذ تجمعات الكائنات (object pools)، أو تحديد النوع الفرعي الذي سيتم إنشاؤه بناءً على معلمات الإدخال.
التحدي
سهللنقم ببناء نظام إشعارات يستخدم منشئات المصنع (factory constructors) لإنشاء أنواع مختلفة من الإشعارات بناءً على مدخل نصي بسيط.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
notification.dart: قم بتعريف فئةNotificationالتي تعمل كقاعدة لجميع أنواع الإشعارات. يجب أن تحتوي الفئة الخاصة بك على:- حقل
String message - منشئ مسمى خاص
Notification._internalيقوم بتهيئة الرسالة - منشئ مصنع
Notification(String type, String message)يقوم بإرجاع أنواع فرعية مختلفة من الإشعارات بناءً على معاملtype:- إذا كان النوع هو
'email'، فقم بإرجاعEmailNotification - إذا كان النوع هو
'sms'، فقم بإرجاعSMSNotification - خلاف ذلك، قم بإرجاع
PushNotification
- إذا كان النوع هو
- دالة
send()تقوم بطباعةSending: [message]
- حقل
في نفس الملف، قم بإنشاء ثلاث فئات فرعية ترث من Notification:
EmailNotification: قم بعمل override للدالةsend()لطباعةEmail: [message]SMSNotification: قم بعمل override للدالةsend()لطباعةSMS: [message]PushNotification: قم بعمل override للدالةsend()لطباعةPush: [message]
تحتاج كل فئة فرعية إلى منشئ يأخذ message ويمررها إلى الفئة الأب باستخدام super._internal(message).
main.dart: قم باستيراد فئة الإشعارات الخاصة بك وإنشاء ثلاثة إشعارات باستخدام منشئ المصنع:- إشعار بريد إلكتروني برسالة
'Welcome!' - إشعار SMS برسالة
'Your code is 1234' - إشعار دفع (push notification) برسالة
'New update available'
send()لكل إشعار بالترتيب المذكور أعلاه.- إشعار بريد إلكتروني برسالة
المخرجات المتوقعة:
Email: Welcome!
SMS: Your code is 1234
Push: New update availableورقة مرجعية
يُعد مُنشئ المصنع (factory constructor) مُنشئاً خاصاً يتم التصريح عنه باستخدام الكلمة المفتاحية factory، وهو لا يقوم دائماً بإنشاء مثيل جديد. وبخلاف المُنشئات العادية، يمكنه إرجاع مثيل موجود بالفعل، أو نوع فرعي، أو null.
لا تملك مُنشئات المصنع وصولاً إلى this ويجب أن تُرجع كائناً بشكل صريح.
مثال على نمط Singleton:
class Logger {
static final Logger _instance = Logger._internal();
Logger._internal(); // Private named constructor
factory Logger() {
return _instance; // Always returns same instance
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueإرجاع أنواع فرعية مختلفة:
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }تُعد مُنشئات المصنع مفيدة للتحكم في إنشاء المثيلات، مثل إرجاع الكائنات المخزنة مؤقتاً (cached objects)، أو تنفيذ تجمعات الكائنات (object pools)، أو تحديد النوع الفرعي الذي سيتم إنشاؤه بناءً على معلمات الإدخال.
جرّب بنفسك
import 'notification.dart';
void main() {
// TODO: إنشاء إشعار بريد إلكتروني مع الرسالة 'Welcome!'
// TODO: إنشاء إشعار SMS مع الرسالة 'Your code is 1234'
// TODO: إنشاء إشعار دفع مع الرسالة 'New update available'
// TODO: استدعاء send() لكل إشعار بالترتيب
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةالمكتبات والـ Importsمقدمة في الـ OOPالـ Classes مقابل الـ Objectsالكلمة المفتاحية thisالـ Methodsمتغيرات الـ Instanceأساسيات الـ Constructorمراجعة - آلة حاسبة بسيطة4أمان الـ Null
مقدمة في أمان الـ NullNullable مقابل Non-Nullableعاملا الـ ? و !الكلمة المفتاحية Late وأمان الـ Nullالعوامل المدركة للـ Nullأمان الـ Null في الـ Classesمراجعة - نظام ملف تعريف المستخدم7الفئات المجردة والواجهات
الفئات المجردةالدوال المجردةالواجهات في Dartالواجهات الضمنيةالتنفيذ مقابل التوسيعالواجهات المتعددةمراجعة - حاسبة الأشكال10المجموعات والأنماط العامة
نظرة عامة على List و Set و Mapالمجموعات آمنة النوعالفئات العامةالدوال العامةقيود الأنماط العامةIterable و Iteratorملخص - التخزين العام13مفاهيم OOP المتقدمة
التركيب مقابل الوراثة (Composition vs Inheritance)دوال التوسعة (Extension Methods)الأصناف القابلة للاستدعاء (Callable Classes)الأصناف المختومة (Sealed Classes - Dart 3)السجلات (Records - Dart 3)الأنماط والمطابقة (Patterns & Matching - 3.0)التعدادات مع الدوال (Enums with Methods)2المنشئات في Dart
المنشئ الافتراضيالمنشئات المسماةقوائم التهيئةالمنشئات الثابتةالمنشئات المصنعيةالمنشئات الموجهةملخص - بناء الأشكال5التغليف (Encapsulation)
الأعضاء العامة مقابل الخاصةاتفاقية البادئة _الخصوصية على مستوى المكتبةتعمق في Getters و Settersإخفاء المعلوماتمراجعة - سجلات الطلاب8Mixins
مقدمة إلى Mixinsإنشاء Mixinsاستخدام Mixins متعددةالكلمة المفتاحية on في MixinsMixin مقابل الوراثة (Inheritance)Mixin مقابل الواجهة (Interface)مراجعة - نظام الحيوانات (Animal System)3خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticحقول Final و Constمتغيرات Lateالـ Static Methods والحقولدوال الـ Getters والـ Settersمراجعة - مدير الحساب البنكي6الوراثة
أساسيات الوراثةالكلمة المفتاحية superإعادة تعريف الدوال (Method Overriding)الوسم @overrideالكلمة المفتاحية final Classالدوال البانية والوراثةمراجعة - هيكلية الموظفين9تعدد الأشكال
أساسيات تعدد الأشكالتعدد الأشكال عبر الـ Interfacesالتحقق من النوع أثناء التشغيلالمعاملات is و asالكلمة المفتاحية Covariantملخص - معالج الدفع12البرمجة الكائنية غير المتزامنة (Async OOP)
Futures و async/awaitأساسيات الـ Streamsمتحكمات الـ Streamsالـ Constructors غير المتزامنةالعمليات غير المتزامنة في دوال الكلاسمراجعة - جالب البيانات (Data Fetcher)15أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع