Dart / الأساسيات: القيم والغياب والمجموعات والكائنات الصالحة / الدرس 5
بناء كائنات صالحة وفهم الخصوصية على مستوى المكتبة
استخدم الحقول ومعاملات التهيئة والمنشئات المسماة والثابتة ودوال القراءة وانتقالات الحالة الصريحة في Dart.
في هذه الصفحة
أهداف الدرس
- ضع الحالة المطلوبة والتحقق عند البناء بدلا من الاعتماد على خطوات إعداد يتذكرها المستدعي.
- ميّز الأسماء الخاصة بالمكتبة والحقول النهائية وهوية الكائن ومساواة القيمة.
اجعل الحالة المطلوبة جاهزة عند اكتمال البناء
يجمع الصنف البيانات والعمليات ويحدد المنشئ كيف يصبح المثيل جاهزا. تسند معاملات التهيئة مثل this.id المدخل إلى الحقل باختصار، ويمكن لقائمة التهيئة تثبيت الحقول قبل تحقق جسم المنشئ وإعداده. فضّل كائنا تعتمد عملياته العامة قيده فور اكتمال البناء. قد تجبر قيمة ابتدائية عامة تخالف المجال كل مستدع على تذكّر إصلاحها. لا تتحقق أنواع الحقول الساكنة من مجالات العمل؛ فافرض تلك القيود صراحة، ولا تفترض أن final أو اسم المنشئ يقدمهما.
اعرض انتقالا يحافظ على القاعدة
يرفض Batch عددا ابتدائيا سالبا ويعرض remaining عبر getter. تعيد consume القيمة false بدلا من جعل العدد سالبا. تجعل الشرطة السفلية _remaining الاسم خاصا بمكتبة Dart، لا بالصنف وحده. تستطيع شيفرة المكتبة نفسها الوصول إليه، لذلك يدخل تنظيم المكتبة ومراجعتها ضمن الحد المقصود. هذا نموذج محلي واحد في الذاكرة، لا تخصيص دائم لعدة مستخدمين. لا يقدم مزامنة بين العوازل أو تخزينا أو منع تكرار الطلب أو حماية بين مثيلات تطبيق منفصلة.
class Batch {
final String id;
int _remaining;
Batch(this.id, int count) : _remaining = count {
if (count < 0) throw ArgumentError.value(count, 'count');
}
int get remaining => _remaining;
bool consume() {
if (_remaining == 0) return false;
_remaining -= 1;
return true;
}
}
void main() {
final batch = Batch('B-9', 1);
print(batch.consume());
print(batch.consume());
print(batch.remaining);
}
true
false
0
المخرج المتوقع true ثم false ثم 0. تحفظ العمليات العامة العدد غير السالب في المثال المتتابع. يستطيع أعضاء المكتبة الوصول إلى الأسماء المسطرة، ولم يُجر اختبار تشغيل أو تزامن.
اختر المنشئ وفقا للوعد الذي يقدمه
تجعل المنشئات المسماة مسارات الإنشاء البديلة صريحة، وليست تحميلات زائدة تُختار باختلاف أنواع المعاملات فقط. يستطيع منشئ const إنشاء مثيلات ثابتة وقت الترجمة عندما تسمح شروطه وسياق الاستدعاء، ويمكن استخدامه أيضا في سياق غير ثابت. وقد يعيد factory مثيلا قائما أو تنفيذا مناسبا آخر بدلا من تخصيص جديد دائما. تؤثر الاختيارات في الهوية والتوقعات؛ فوثّق التخزين المؤقت والتحقق المهمين. تجنب منشئات تتفق أسماؤها ظاهريا وتختلف بصمت حول قيد تفترضه العمليات العامة.
تحتاج الهوية ومساواة القيمة تحليلا مختلفا
تفحص identical هل يشير مرجعان إلى الكائن نفسه. تعتمد مساواة الأصناف العادية الهوية افتراضيا ما لم يعرّف التنفيذ عقدا آخر. قد تجعل مشاركة الثوابت المعيارية إنشاءين ثابتين متكافئين يشتركان في الهوية؛ ولا يثبت ذلك مساواة قيمية لكل سجلين منفصلين. إذا تجاوزت == فحافظ على اتساق hashCode وتجنب حقولا معدلة تحدد مساواة مفتاح تجزئة. يعرض المثال قيمة const ومنشئا بديلا مسمى فقط. لا ينفذ معرفا متحققا كاملا ولا يعد بثبات عميق لحقول متداخلة اعتباطية.
class SampleLabel {
final String id;
const SampleLabel(this.id);
SampleLabel.unknown() : id = 'unknown';
String get display => id.toUpperCase();
}
void main() {
const first = SampleLabel('lab');
const second = SampleLabel('lab');
print(identical(first, second));
print(first.display);
print(SampleLabel.unknown().id);
}
true
LAB
unknown
المخرج المتوقع true ثم LAB ثم unknown. يشترك المثيلان الثابتان المتكافئان في التمثيل المعياري. لم يُترجم المصدر، وتسمية unknown بديل تعليمي لا معرف عمل صالح.
عامل سطح الصنف كعقد يمكن الاستبدال وفقه
تعرّف أصناف Dart واجهات ضمنية من أعضائها العامة للمثيل. لا يرث تنفيذ تلك الواجهة الشيفرة الأصلية أو الحالة الخاصة. لذلك تحل الوراثة وتنفيذ الواجهة وإعادة الاستخدام عبر mixin مشكلات مختلفة، وتخضع لقيود معدلات تُشرح لاحقا. فضّل التركيب عندما يستخدم الكائن قدرة بدلا من أن يستبدل نوعا حقا. اجعل getters غير مفاجئة؛ فقد تخالف خاصية تبدو بسيطة توقعات المستدعي إذا أجرت إدخالا وإخراجا خفيا أو تعديلا مكلفا. وثّق الآثار والملكية عند حد الواجهة، ولا تعتمد على صياغة الكائنات لنقلهما تلقائيا.
الأخطاء الشائعة وإصلاحها
يُفترض أن الحقل المسطر لا تصل إليه أي أصناف أخرى.
- لماذا يحدث؟
- اختلطت خصوصية المكتبة بخصوصية الصنف وحده.
- كيف تصلحه؟
- راجع حد المكتبة الفعلي، وامنع تعديل الأقران غير المقصود بالتصميم.
- كيف تتجنب تكراره؟
- وثّق الملكية داخل المكتبة إلى جانب سطحها العام.
ينشئ أحد المنشئات المسماة حالة غير صالحة تقبلها العمليات العامة.
- لماذا يحدث؟
- ارتبط التحقق بمسار إنشاء واحد فقط.
- كيف تصلحه؟
- اجعل كل مسار إنشاء مسموح يثبت القيد المشترك.
- كيف تتجنب تكراره؟
- اختبر كل منشئ وفق قيود المجال نفسها.
يصعب العثور بثبات على مفتاح عُدّل داخل حاوية تجزئة.
- لماذا يحدث؟
- تغيرت الحالة المحددة للمساواة بعد الإدراج.
- كيف تصلحه؟
- استخدم مفاتيح قيمية ثابتة وسلوكا متسقا لـ== وhashCode.
- كيف تتجنب تكراره؟
- راجع المساواة والتعديل معا قبل استخدام نموذج كمفتاح.
اختبر فهمك
1. هل يجعل حقل final يحمل قائمة قابلة للتعديل الصنف ثابتا بعمق؟
اعرض الحل المشروح
لا. لا يستبدل مرجع الحقل بعد التهيئة، لكن قد تتغير القائمة وكائنات عناصرها المعدلة عبر مراجع أخرى. اختر لقطة غير قابلة للتعديل ونموذج عناصر ثابتا مناسبين، أو ملكية صريحة. ولمنشئ const شروط منفصلة؛ فلا يجمد بأثر رجعي رسم كائنات final اعتباطيا.
2. لماذا ينبغي أن توثّق الواجهة هل يعيد factory مثيلات مخزنة مؤقتا؟
اعرض الحل المشروح
قد يفترض المستدعي خلاف ذلك حالة مستقلة أو يستخدم الهوية للتتبع. قد يكشف إعادة المثيل تعديلا مشتركا أو تداخل أعمار ما لم يكن النوع قيميا آمنا. وثّق العقد، ولا تجعل التخصيص إشارة ضمنية غير موثقة، واختبر ما يُسمح للمستدعي بملاحظته فعليا.
أهم ما تعلمته
- يجب أن تثبت مسارات البناء وانتقالات الحالة القيد نفسه.
- خصوصية المكتبة ومراجع final والكائنات الثابتة ومساواة القيمة آليات مختلفة.