الفئات العامة
جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 65 من 110.
لقد رأيت كيف تستخدم مجموعات Dart المدمجة مثل List<String> معلمات النوع. الآن حان الوقت لإنشاء فئاتك العامة (generic classes) الخاصة التي تعمل مع أي نوع تحدده.
تستخدم الفئة العامة (generic class) معامل نوع (عادةً ما يكون T) كعنصر نائب للنوع الفعلي الذي سيتم توفيره عند إنشاء مثيل:
class Box<T> {
T content;
Box(this.content);
T getContent() => content;
}
void main() {
var stringBox = Box<String>('Hello');
var intBox = Box<int>(42);
print(stringBox.getContent()); // Hello
print(intBox.getContent()); // 42
}يعمل T كمتغير نوع - فعندما تقوم بإنشاء Box<String>، فإن كل T في الفئة يصبح String. يوفر لك هذا أمان النوع (type safety) دون الحاجة لكتابة فئات منفصلة لكل نوع.
يمكنك استخدام معلمات أنواع متعددة عندما يحتاج صنفك (class) إلى العمل مع أكثر من نوع واحد:
class Pair<K, V> {
K first;
V second;
Pair(this.first, this.second);
}
void main() {
var pair = Pair<String, int>('age', 25);
print('${pair.first}: ${pair.second}'); // age: 25
}تُعد الفئات العامة (Generic classes) هي الأساس لكتابة كود برمجي قابل لإعادة الاستخدام وآمن من حيث النوع (type-safe). فبدلاً من تكرار المنطق لأنواع مختلفة أو فقدان معلومات النوع باستخدام dynamic، تتيح لك القوالب العامة (generics) كتابة كود مرن لا يزال بإمكان المترجم (compiler) التحقق منه.
التحدي
سهللنقم ببناء نظام لتغليف الهدايا يستخدم أصنافاً عامة (generic classes) لإنشاء حاويات مرنة لأنواع مختلفة من العناصر. ستقوم بإنشاء صنف عام Wrapper يمكنه تغليف أي نوع من المحتوى، وصنف GiftBox بمعاملين للنوع لربط هدية مع رسالة بطاقة.
ستقوم بتنظيم الكود الخاص بك في ملفين:
wrapper.dart: قم بتعريف الأصناف العامة هنا:- صنف عام
Wrapper<T>مع خاصيةT contentومنشئ (constructor). قم بتضمين دالةunwrap()التي تعيد المحتوى، ودالةdescribe()التي تطبعWrapped: [content] - صنف عام
GiftBox<G, C>مع خاصيتين:G giftوC card. قم بتضمين منشئ ودالةopen()تطبعGift: [gift]في سطر وCard: [card]في السطر التالي
- صنف عام
main.dart: قم باستيراد ملف wrapper واستعرض الأصناف العامة مع أنواع مختلفة:- أنشئ
Wrapper<String>يحتوي على'Chocolate'واستدعِdescribe() - أنشئ
Wrapper<int>يحتوي على42واستدعِdescribe() - أنشئ
Wrapper<double>يحتوي على3.14واستدعِdescribe() - اطبع سطراً فارغاً
- أنشئ
GiftBox<String, String>مع هدية'Teddy Bear'وبطاقة'Happy Birthday!'، ثم استدعِopen() - اطبع سطراً فارغاً
- أنشئ
GiftBox<int, String>مع هدية100(تمثل مبلغ بطاقة هدايا) وبطاقة'Congratulations!'، ثم استدعِopen()
- أنشئ
لاحظ كيف يعمل نفس الصنف Wrapper بسلاسة مع النصوص، والأعداد الصحيحة، والأعداد العشرية. يوضح صنف GiftBox استخدام معملين للنوع لربط أنواع مختلفة معاً - حيث يمكن أن تكون الهدية من أي نوع بينما تظل رسالة البطاقة نصاً.
المخرجات المتوقعة:
Wrapped: Chocolate
Wrapped: 42
Wrapped: 3.14
Gift: Teddy Bear
Card: Happy Birthday!
Gift: 100
Card: Congratulations!ورقة مرجعية
تستخدم الأصناف العامة (Generic classes) معاملات النوع (مثل T) كعناصر نائبة للأنواع الفعلية المحددة عند إنشاء المثيلات:
class Box<T> {
T content;
Box(this.content);
T getContent() => content;
}
void main() {
var stringBox = Box<String>('Hello');
var intBox = Box<int>(42);
print(stringBox.getContent()); // Hello
print(intBox.getContent()); // 42
}عند إنشاء Box<String>، يصبح كل T في الصنف String، مما يوفر سلامة النوع (type safety) دون الحاجة إلى أصناف منفصلة لكل نوع.
استخدم معاملات نوع متعددة عند العمل مع أكثر من نوع واحد:
class Pair<K, V> {
K first;
V second;
Pair(this.first, this.second);
}
void main() {
var pair = Pair<String, int>('age', 25);
print('${pair.first}: ${pair.second}'); // age: 25
}جرّب بنفسك
import 'wrapper.dart';
void main() {
// TODO: قم بإنشاء Wrapper<String> يحتوي على 'Chocolate' واستدعِ describe()
// TODO: قم بإنشاء Wrapper<int> يحتوي على 42 واستدعِ describe()
// TODO: قم بإنشاء Wrapper<double> يحتوي على 3.14 واستدعِ describe()
// TODO: اطبع سطراً فارغاً
// TODO: قم بإنشاء GiftBox<String, String> مع الهدية 'Teddy Bear'
// والبطاقة 'Happy Birthday!'، ثم استدعِ open()
// TODO: اطبع سطراً فارغاً
// TODO: قم بإنشاء GiftBox<int, String> مع الهدية 100
// والبطاقة 'Congratulations!'، ثم استدعِ open()
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع