في الدروس الماضية تحدثنا عن الـ Interface والـ Abstract Class. الآن سنضعهما جنباً إلى جنب لنرى متى نستخدم كل واحد منهما.
قبل Java 8، كانت الـ Interface تحتوي فقط على abstract methods - أي أن جميع الدوال المجردة يجب أن تتم تنفيذها من قبل الفئة التي تطبقها.
منذ Java 8، يمكننا إضافة default implementation، لكن هذا يُستخدم فقط لأغراض التوافقية العكسية (backward compatibility) في الحالات التي يكون فيها التطبيق معقداً جداً.
public interface Payment {
// جميع الميثودات public by default
void pay(double amount);
}
جميع الميثودات في الـ Interface هي public افتراضياً.
public interface Payment {
// هذا غير صحيح - لا يمكن إضافة constructor
// public Payment() {}
}
الـ Interface لا تحتوي على constructors.
public interface Payment {
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
إذا أضفت متغيراً في الـ Interface، يجب أن يكون public static final تلقائياً.
public interface Payment {
void pay();
}
public interface Refundable {
void refund();
}
// يمكن تطبيق عدة interfaces
public class CreditCard implements Payment, Refundable {
@Override
public void pay() {
// التنفيذ
}
@Override
public void refund() {
// التنفيذ
}
}يمكن لفئة واحدة أن تطبق عدداً لا نهائياً من الـ Interfaces - لا توجد حدود هنا.
public abstract class Payment {
// abstract method
abstract void pay();
// concrete method (default implementation)
void validateTransaction() {
System.out.println("Validating...");
}
}الـ Abstract Class يمكن أن تحتوي على كلا النوعين من الميثودات.
public abstract class Payment {
private double amount;
protected String transactionId;
public static final double MAX_AMOUNT = 10000;
// يمكن تعديل هذه المتغيرات بحرية
}بخلاف الـ Interface، يمكن لديك متغيرات private، protected، أو حتى بدون final.
public abstract class Payment {
public Payment(double amount) {
this.amount = amount;
}
}الـ Abstract Class يمكن أن تحتوي على constructors لتهيئة البيانات.
public abstract class Payment {
public abstract void pay();
protected abstract void validate();
private void logTransaction() {
// يمكن أن تكون private
}
}يمكن استخدام أي access modifier للميثودات (public، protected، private).
public class CreditCard extends Payment {
// يمكن extend فئة واحدة فقط
}
// هذا غير صحيح:
// public class CreditCard extends Payment, AnotherAbstractClass {}بخلاف الـ Interface، يمكن لفئة واحدة أن extend فئة جردة واحدة فقط.
| الخاصية | Interface | Abstract Class |
|---|---|---|
| Abstract Methods | ✓ | ✓ |
| Default Implementation | ✓ (Java 8+) | ✓ |
| المتغيرات | public static final فقط | أي نوع |
| Constructors | ✗ | ✓ |
| Access Modifiers | public فقط | أي نوع |
| Multiple Implementation/Extension | implement عدة interfaces | extend واحد فقط |
تريد تحديد عقد (contract) لعدة فئات
إذا كان لديك متطلب معين يجب أن تتبعه فئات متعددة من مجالات مختلفة، استخدم Interface.
الفئات التي تطبق الـ Interface قد تكون من أماكن مختلفة تماماً - لا يشترط أن تكون مرتبطة ببعضها.
تريد مشاركة سلوك مشترك بين الفئات الوسيطة
إذا كان لديك مجموعة من الفئات المرتبطة بعلاقة تسلسلية، استخدم Abstract Class.
على سبيل المثال، جميع أنواع الدفع تشترك في سلوك التحقق من المعاملة (validate payment).
تريد مزج abstract و concrete methods
إذا كنت بحاجة إلى بعض الميثودات المجردة وبعض الميثودات ذات التنفيذ الفعلي، استخدم Abstract Class.
الفئات مرتبطة منطقياً
الـ Abstract Class أفضل عندما تكون الفئات الوسيطة مرتبطة ببعضها البعض من الناحية المنطقية والبنيوية.