التنفيذ مقابل التوسيع
جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 47 من 110.
الآن بعد أن فهمت كلاً من extends و implements، دعنا نوضح متى نستخدم كل منهما.
استخدم extends عندما تريد وراثة السلوك. تحصل الفئة الفرعية (subclass) الخاصة بك على جميع أكواد الفئة الأب مجانًا ويمكنها البناء عليها:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // موروثة - تعمل تلقائيًا
dog.bark();
}استخدم implements عندما تريد ضمان هيكلية معينة دون وراثة الكود. يجب عليك كتابة كل دالة بنفسك:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...'); // تنفيذ مخصص بالكامل
}
}الفرق الجوهري: extends يقول "أنا نوع من هذا" بينما implements يقول "يمكنني القيام بما يفعله هذا." الـ Dog هو Animal ويتنفس بنفس الطريقة. الـ Robot ليس حيواناً، ولكنه يمكنه الوفاء بنفس العقد بمنطقه الخاص.
تذكر: يمكنك توسيع فئة واحدة فقط، ولكن يمكنك تنفيذ العديد من الواجهات. اختر extends لعلاقات الوراثة الحقيقية، و implements عندما تحتاج إلى المرونة أو ترغب في فرض عقد دون مشاركة تفاصيل التنفيذ.
التحدي
سهللنقم ببناء نظام عمال يوضح متى نستخدم extends مقابل implements. ستقوم بإنشاء فئة أساسية للعامل ثم توضح كلا النهجين: فئة واحدة "هي" عامل حقاً وترث السلوك، وأخرى ببساطة "يمكنها القيام" بما يفعله العامل ولكن بمنطق مخصص تماماً.
ستقوم بتنظيم الكود الخاص بك في ملفين:
worker.dart: حدد التسلسل الهرمي للعمال هنا:- فئة
Workerمع خاصيةString nameومنشئ (constructor). قم بتضمين تابعwork()يطبع[name] is working...وتابعtakeBreak()يطبع[name] takes a coffee break - فئة
OfficeWorkerالتي ترث (extends) منWorker. أضف خاصيةString department. قم بإعادة تعريف (Override) لـwork()ليطبع[name] is typing reports in [department]مع الاحتفاظ بسلوكtakeBreak()الموروث - فئة
RobotWorkerالتي تطبق (implements) واجهةWorker. أضف خاصيةString model. بما أن الروبوتات ليست عمالاً حقاً ولكن يمكنها القيام بما يفعله العمال، فقم بتوفير تطبيقات مخصصة تماماً: يجب أن يطبعwork()النصRobot [model] is assembling partsويجب أن يطبعtakeBreak()النصRobot [model] is recharging
- فئة
main.dart: استورد ملف العامل وقم باستعراض كلا النهجين:- أنشئ
OfficeWorkerباسم'Alice'في قسم'Marketing' - أنشئ
RobotWorkerبطراز'RX-7' - بالنسبة لموظف المكتب، استدعِ
work()ثمtakeBreak() - اطبع سطراً فارغاً
- بالنسبة للعامل الروبوت، استدعِ
work()ثمtakeBreak()
- أنشئ
لاحظ كيف يرث OfficeWorker التابع takeBreak() تلقائياً لأنه يمتد من Worker - فهو "عامل" حقاً. وفي الوقت نفسه، يجب على RobotWorker توفير تطبيقه الخاص لكل شيء لأنه يطبق الواجهة فقط - فهو "يمكنه القيام" بما يفعله العامل، ولكن بطريقته الروبوتية الخاصة.
المخرجات المتوقعة:
Alice is typing reports in Marketing
Alice takes a coffee break
Robot RX-7 is assembling parts
Robot RX-7 is rechargingورقة مرجعية
استخدم extends لوراثة السلوك من فئة أب (parent class). تحصل الفئة الفرعية (subclass) تلقائياً على جميع دوال الأب ويمكنها تجاوزها (override):
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Inherited automatically
dog.bark();
}استخدم implements لضمان هيكلية معينة دون وراثة الكود. يجب عليك تقديم التنفيذ الخاص بك (implementation) لكل دالة:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...');
}
}الاختلافات الرئيسية:
extends: "أنا نوع من هذا" - وراثة حقيقية مع كود مشتركimplements: "يمكنني القيام بما يفعله هذا" - يفرض عقداً (contract) بمنطق مخصص- يمكنك تمديد (extend) فئة واحدة فقط، ولكن يمكنك تنفيذ (implement) واجهات متعددة
اختر extends لعلاقات الأب والابن الحقيقية حيث يجب وراثة السلوك. اختر implements عندما تحتاج إلى المرونة أو تريد فرض عقد دون مشاركة التنفيذ.
جرّب بنفسك
import 'worker.dart';
void main() {
// TODO: 'Marketing' في قسم 'Alice' باسم OfficeWorker أنشئ
// TODO: 'RX-7' بطراز RobotWorker أنشئ
// TODO: ثم استدعِ ()takeBreak وبعدها ()work استدعِ ،OfficeWorker بالنسبة لـ
// TODO: اطبع سطرًا فارغًا
// TODO: ثم استدعِ ()takeBreak وبعدها ()work استدعِ ،RobotWorker بالنسبة لـ
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع