✅ أولاً: ما هو الـ Interface؟
📘 التعريف:
interface
هو عقد (contract) يحدد ما الذي يجب على الكلاس تنفيذه، لكنه لا يحتوي على أي منطق (body).
في Dart، لا يوجد keyword خاصة بـ interface
، وإنما كل class
يمكن اعتباره interface عند استخدامه مع implements
.
🧠 كيف نستخدمه؟
- Dart تعوض
interface
بالكلمة المفتاحية: implements
.
- الكلاس الذي يطبّق (implements) interface يجب أن ينفذ كل شيء فيه حرفيًا.
✅ لماذا نستخدم interface؟
الهدف | الشرح |
---|
✅ فصل السلوك عن التنفيذ | الكلاس يحدد فقط “ما يجب فعله” وليس “كيف” |
✅ قابلية التوسعة | أي كلاس يمكنه تنفيذ الواجهة بطريقته |
✅ دعم الوراثة المتعددة | Dart لا تدعم extends لأكثر من كلاس، لكن تدعم implements لعدة واجهات |
✅ يساعد في كتابة كود مرن وقابل للاختبار | لأنه يفصل بين الكود الفعلي والتجريد |
✅ الشكل العام:
class InterfaceName {
void method1();
int method2(String name);
}
class MyClass implements InterfaceName {
@override
void method1() {
// تنفيذ خاص بالكلاس
}
@override
int method2(String name) {
return name.length;
}
}
Dart
✅ مثال 1: واجهة تسجيل الدخول
class AuthService {
void login(String email, String password);
}
class FirebaseAuth implements AuthService {
@override
void login(String email, String password) {
print("تسجيل الدخول باستخدام Firebase");
}
}
class LocalAuth implements AuthService {
@override
void login(String email, String password) {
print("تسجيل الدخول المحلي");
}
}
void main() {
AuthService auth = FirebaseAuth();
auth.login("[email protected]", "123456");
}
Dart
✅ شرح المثال:
- أنشأنا
AuthService
كـ واجهة: تحتوي فقط على الدالة login
بدون body.
FirebaseAuth
و LocalAuth
قاموا بـ implements
للواجهة ونفذوا دالة login
بطريقتهم.
- الكود صار مرن: تقدر تستبدل طريقة تسجيل الدخول بسهولة دون تغيير منطق البرنامج.
✅ ملاحظات مهمة جدًا:
المعلومة | التوضيح |
---|
❌ لا يمكن ترك دالة بدون تنفيذ | يجب تنفيذ كل الدوال الموجودة في الواجهة |
✅ يمكن تنفيذ عدة واجهات معًا | Dart تدعم implements A, B, C... |
✅ الواجهة لا تحتوي خصائص final أو متغيرات منجزة | فقط التصريحات (declarations) |
✅ الواجهة لا تنفذ شيء | فقط تحدد ما يجب تنفيذه |
✅ مثال 2: حيوانات لها صوت
class SoundMaker {
void makeSound();
}
class Dog implements SoundMaker {
@override
void makeSound() {
print("هاو هاو 🐶");
}
}
class Cat implements SoundMaker {
@override
void makeSound() {
print("مياو 🐱");
}
}
Dart
✅ الفرق بين implements
و extends
و abstract class
المقارنة | abstract class | interface (implements ) | extends (وراثة عادية) |
---|
يحتوي منطق (دوال عادية)؟ | ✅ نعم | ❌ لا | ✅ نعم |
يجب تنفيذ الدوال المجردة؟ | ✅ نعم | ✅ نعم | ❌ لا |
يرث من كلاس واحد فقط؟ | ✅ نعم | ❌ يمكن من عدة واجهات | ✅ نعم |
يمكن استخدام الخصائص؟ | ✅ نعم | ❌ فقط الدوال | ✅ نعم |
وراثة كاملة للسلوك؟ | ❌ جزئي | ❌ لا | ✅ نعم |
✅ استخدام أكثر من واجهة:
class Printable {
void printInfo();
}
class Saveable {
void save();
}
class Document implements Printable, Saveable {
@override
void printInfo() => print("طباعة المستند");
@override
void save() => print("حفظ المستند");
}
Dart
وهكذا جعلنا Document
يجمع بين وظيفتين مختلفتين.
✅ متى تستخدم interface؟ ومتى abstract class؟
الحالة | استخدم interface | استخدم abstract class |
---|
عند الحاجة لتعريف هيكل بدون تنفيذ | ✅ | ❌ |
عند الحاجة لمنطق مشترك بين الأبناء | ❌ | ✅ |
عند الحاجة لتنفيذ أكثر من نوع | ✅ | ❌ |
تريد فرض تنفيذ 100% للدوال | ✅ | ❌ |
تريد مرونة كبيرة بالوراثة | ✅ (لأنها متعددة) | ❌ (واحدة فقط) |
✅ خلاصة شاملة:
العنصر | التوضيح |
---|
interface | مجرد عقد يجب على الكلاس تنفيذه |
implements | الطريقة التي نطبق بها interface |
يجب تنفيذ كل شيء | أي دالة في الواجهة يجب تنفيذها بالكامل |
مناسب لـ polymorphism والاختبار | لأنه يتيح لك تبديل التنفيذ بسهولة |
لا يمكن إنشاء كائن من interface | لأنها ليست كلاس كامل التنفيذ |