المنشئات في Dart: حالات الاستخدام وأمثلة عملية
مقدمة إلى المنشئات في Dart
تُعد المنشئات Constructors من المفاهيم الأساسية في البرمجة كائنية التوجه، لأنها المسؤولة عن إنشاء كائنات جديدة من الأصناف Classes. ومن خلالها يمكن تحديد البيانات المطلوبة عند إنشاء الكائن، وتنظيم منطق التهيئة الداخلي بطريقة واضحة وآمنة.
في لغة Dart، تؤدي المنشئات هذا الدور التقليدي، لكنها توفر أيضاً أساليب متقدمة لا نجدها بهذا الشكل في كثير من اللغات الأخرى. وهذا ما يجعل فهمها مهماً لكل مطور يريد كتابة شيفرة نظيفة، قابلة للتوسعة، وسهلة الصيانة.

في هذا المقال سنستعرض أهم أنواع المنشئات في Dart، مع أمثلة عملية توضّح متى يُستخدم كل نوع، وكيف تختار الأنسب لاحتياجك البرمجي.
الصنف المستخدم في الأمثلة
سنستخدم الصنف التالي كنموذج أساسي في معظم الأمثلة:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
}
كيف تبدأ مع المنشئات في Dart؟
إذا لم تقم بتعريف أي منشئ داخل الصنف في Dart، فستوفّر اللغة منشئاً افتراضياً Default Constructor بشكل ضمني. هذا المنشئ لا يظهر أمامك داخل الشيفرة، لكنه يُستخدم عند إنشاء كائن جديد من الصنف.
المنشئ الافتراضي لا يستقبل أي معاملات Arguments، ويستدعي أيضاً منشئ الصنف الأب super بدون معاملات.
ولتعريف منشئ مخصص داخل الصنف، يمكن كتابة شيء مثل الآتي:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(String make, String model, int year, bool hasABS) {
this.make = make;
this.model = model;
this.yearMade = year;
this.hasABS = hasABS;
}
}
هذه الطريقة تعمل، لكنها ليست الأكثر أناقة. ولهذا توفر Dart أسلوباً مختصراً لتعيين القيم مباشرة إلى خصائص الصنف:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
}
هذا الأسلوب هو مجرد تبسيط نحوي Syntactic Sugar يجعل الشيفرة أقصر وأكثر وضوحاً، خاصة عند التعامل مع خصائص كثيرة.

ميزات أكثر تقدماً للمنشئات في Dart
في بعض لغات البرمجة، يمكن استخدام التحميل الزائد للمنشئات Constructor Overloading، أي إنشاء أكثر من منشئ بالاسم نفسه لكن بمعاملات مختلفة.
أما في Dart، فلا يمكن تطبيق هذا الأسلوب بالطريقة التقليدية، لكن اللغة تقدم بديلاً عملياً ومرناً جداً: المنشئات المسمّاة Named Constructors.
المنشئات المسمّاة في Dart
تسمح لك المنشئات المسمّاة بإنشاء أكثر من منشئ للصنف نفسه، مع إعطاء كل منشئ اسماً يوضح غرضه. وهذا يجعل الشيفرة أكثر قابلية للفهم عند استخدامها من خارج الصنف.
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
Car.withoutABS(this.make, this.model, this.yearMade)
: hasABS = false;
}
في المثال السابق، يقوم المنشئ Car.withoutABS بتهيئة الخاصية hasABS بالقيمة false قبل تنفيذ جسم المنشئ. ويُعرف هذا الأسلوب باسم قائمة التهيئة Initializer List.
يمكن استخدام قائمة التهيئة لتهيئة أكثر من متغير، مع الفصل بينها بفواصل. ومن أكثر استخداماتها شيوعاً تهيئة الخصائص المعلنة بالكلمة final.
- تُنفَّذ قائمة التهيئة قبل جسم المنشئ.
- تُستخدم كثيراً مع الخصائص غير القابلة للتغيير.
- لا يمكن استخدام
thisفي الجزء الواقع على يمين النقطتين:.
المنشئات المصنعّية Factory Constructors في Dart
المنشئ المصنعّي factory هو منشئ لا يُشترط أن ينشئ كائناً جديداً في كل مرة. وهذه ميزة مهمة في حالات معينة، مثل:
- إعادة استخدام كائنات موجودة مسبقاً في الذاكرة.
- تقليل تكلفة إنشاء الكائنات إذا كانت عملية الإنشاء معقدة.
- تنفيذ منطق خاص قبل إرجاع الكائن المناسب.
إليك المثال التالي:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
factory Car.ford(String model, String yearMade, bool hasABS) {
return FordCar(model, yearMade, hasABS);
}
}
class FordCar extends Car {
FordCar(String model, String yearMade, bool hasABS)
: super("Ford", model, yearMade, hasABS);
}
هنا، المنشئ Car.ford لا ينشئ مباشرة كائناً من الصنف Car، بل يعيد كائناً من الصنف الفرعي FordCar. وهذا يوضح مدى مرونة المنشئات المصنعّية في تصميم الواجهات البرمجية APIs بشكل احترافي.
أنواع متقدمة من المنشئات في Dart
المنشئات الثابتة Constant Constructors
إذا كان الصنف يمثل كائناً لن تتغير حالته بعد الإنشاء، فيمكنك الاستفادة من المنشئات الثابتة const constructors. هذا مفيد لتحسين الأداء وتقليل إنشاء نسخ متطابقة غير ضرورية.
لكن لاستخدام هذا النوع، يجب أن تكون جميع خصائص الصنف معلنة باستخدام final.
class FordFocus {
static const FordFocus fordFocus = FordFocus(
"Ford",
"Focus",
"2013",
true,
);
final String make;
final String model;
final String yearMade;
final bool hasABS;
const FordFocus(this.make, this.model, this.yearMade, this.hasABS);
}
هذا النوع مناسب جداً للكائنات الثابتة التي لا تحتاج إلى تعديل، مثل الإعدادات المسبقة أو القيم المرجعية المعروفة.
المنشئات التحويلية Redirecting Constructors
في بعض الأحيان، تحتاج إلى أن يستدعي منشئ معين منشئاً آخر داخل الصنف نفسه، بدلاً من تكرار منطق التهيئة. في Dart، يُعرف هذا الأسلوب باسم المنشئات التحويلية Redirecting Constructors.
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
Car.withoutABS(this.make, this.model, this.yearMade)
: this(make, model, yearMade, false);
}
الميزة هنا أنك تعيد استخدام منشئ أساسي موجود مسبقاً، مما يقلل التكرار ويحافظ على اتساق منطق الإنشاء داخل الصنف.
متى تستخدم كل نوع من المنشئات؟
| نوع المنشئ | أفضل استخدام |
|---|---|
Default Constructor |
عند الاكتفاء بإنشاء بسيط دون منطق خاص. |
Named Constructor |
عند الحاجة إلى أكثر من طريقة واضحة لإنشاء الكائن. |
factory |
عند إعادة استخدام الكائنات أو إرجاع نوع فرعي أو تنفيذ منطق متقدم. |
const Constructor |
عند التعامل مع كائنات ثابتة غير قابلة للتغيير. |
Redirecting Constructor |
عند الرغبة في استدعاء منشئ آخر داخل الصنف نفسه لتقليل التكرار. |
أفضل ممارسات عند كتابة المنشئات في Dart
- اختر أسماء واضحة للمنشئات المسمّاة حتى يكون الغرض منها مفهوماً فوراً.
- استخدم قائمة التهيئة
Initializer Listعندما تحتاج إلى تهيئة خصائصfinal. - لا تُكثر من المنطق المعقد داخل المنشئ إن كان يمكن نقله إلى طريقة مستقلة.
- اعتمد على
factoryعندما تريد مرونة أكبر في إنشاء الكائنات. - استخدم
constكلما كان الكائن ثابتاً فعلاً، لأن ذلك قد يحسن الأداء واستهلاك الذاكرة.
الخلاصة التقنية
توفر لغة Dart نظام منشئات مرناً وقوياً، يبدأ من الأساسيات البسيطة وينتقل إلى أنماط متقدمة تناسب التطبيقات الكبيرة. الفهم الجيد للفرق بين المنشئ الافتراضي، والمسمّى، والمصنعّي، والثابت، والتحويلي يساعدك على كتابة شيفرة أوضح وأكثر احترافية. ومن الناحية التقنية، فإن الاختيار الصحيح لنوع المنشئ لا يحسن تصميم الصنف فقط، بل ينعكس أيضاً على سهولة الصيانة، وإعادة الاستخدام، وكفاءة التطبيق على المدى الطويل.