مفهوم الـ Abstraction
تجريد: تعني Abstraction في اللغة الإنجليزية, و هو أسلوب مهم جداً يستخدم لتسهيل كتابة الأوامر على المبرمجين, فهو يجعلك قادراً على تنفيذ ما تريد دون الحاجة إلى معرفة كافة التفاصيل التي تم فيها تنفيذ ذلك. إذاً الـ Abstraction يجعلك تتعامل مع الأشياء بسطحية بدل أن تغوص في معرفة تفاصيل الكودات المعقدة.
فمثلاً إذا كنت تنوي بناء برنامج يتيح لمستخدميه إرسال إقتراحات حول التطبيق من خلال البريد الإلكتروني, في هذه الحالة لن يكون عليك القلق بتاتاً حول طريقة تعامل أوامر جافا مع البروتوكولات التي تعمل عندما يتم إرسال رسائل إلكترونية من خلال هذا التطبيق, لأنك لست مسؤولاً عنها, فعلياً هذه وظيفة شركة Sun التي تقوم بتطوير لغة جافا. و هم يخبرونك أنه لإرسال بريد إلكتروني إستخدم هذه الأوامر البسيطة فقط.
إذاً الـ Abstraction هو أسلوب يستخدم لإخفاء تفاصيل تنفيذ البرنامج. لتطبيق مفهوم الـ Abstraction نستخدم الكلمة abstract ضمن شروط محددة.
مصطلحات تقنية
إذا أردت تعريف الشيء كـ abstract, أكتب فقط الكلمة abstract قبله.
الكلاس المعرف كـ
abstractيسمى Abstract Class.الكلاس العادي الغير معرف كـ
abstractيسمى Concrete Class.الدالة المعرفة كـ
abstractتسمى Abstract Method أو Abstract Function.
Abstract Class
إذا وضعت الكلمة abstract قبل إسم الكلاس, ستتغير قليلاً طريقة التعامل معه لأنه لم يعد كلاس عادي. و عندها سيراه المترجم كـ Abstract Class.
نقاط مهمة حول الـ Abstract Class
الكلاس العادي لا يمكنه أن يحتوي على دوال نوعها
abstract.الـ Abstract Class يمكنه أن يحتوي على دوال عادية, و يمكنه أن يحتوي على دوال نوعها
abstract.إذا قمت بتعريف الكلاس كـ
abstract, فهذا يعني أن هذا الكلاس لا يمكن إنشاء كائنات منه.بما أنه لا يمكن إنشاء كائنات من Abstract Class, فهذا يعني أنه للإستفادة من هذا الكلاس, يجب وراثته.
الكلاس الذي يرث من كلاس نوعه
abstract, يجب أن يفعل Override لجميع الدوال المعرفة كـabstract.
طريقة تعريف كلاس نوعه abstract
نكتب فقط الكلمة abstract قبل الكلمة class.
مثال
abstract class Example {
}
Abstract Method
إذا كنت تريد بناء دالة و جعل الكلاس الذي يرثها هو المسؤول عن كتابتة محتواها, قم بتعريفها كـ abstract.
نقاط مهمة حول الـ Abstract Method
إذا وضعت الكلمة
abstractقبل إسم الدالة, فهذا يعني أنها دالة من النوعabstract.الدالة التي نوعها
abstractهي دالة لها إسم و نوع محدد, لكنها لا تحتوي على body (جسم), أي لا تملك أقواس بداية و نهاية{ }.الدالة العادية تحتوي على أقواس البداية و النهاية
{ }.الـ Abstract Method يجب وضع فاصلة منقوطة
;في آخرها بدل أقواس البداية و النهاية.الكلاس الذي يرث من كلاس نوعه
abstract, يجب أن يفعل Override لكل دوالة نوعهاabstract, أي يجب أن يكتب الـ body لهذه الدوال.
طريقة تعريف دوال نوعها abstract
نكتب فقط الكلمة abstract بعد Modifier الدالة.
أمثلة
public abstract void print(); public abstract int getId(); public abstract void setId(int id);
إنتبه: عندما تفعل Override لدالة نوعها abstract, يجب أن لا تعرفها كـ abstract من جديد.
مثال
•لنفترض أننا قمنا بتعريف دالة إسمها displayMessage() كـ abstract.
public abstract void displayMessage();
•لا يجب أن نكتب abstract عندما تفعل لها Override.
@Override
public abstract void displayMessage() { // abstract methods cannot have a body
•لتصحيح هذا الخطأ, نمسح فقط الكلمة abstract.
@Override
public void displayMessage() { // نلاحظ أن التنبيه إختفى
}
أمثلة شاملة
وضعنا هنا ثلاثة أمثلة بسيطة و مترابطة تعلمك الأساسيات.
وضعنا هنا مثال بسيط حول Abstract Class يرث من Abstract Class.
وضعنا هنا مثال مهم يعلمك متى تحتاج إلى إنشاء Abstract Class.
سترى فائدة الـ Abstraction أيضاً في دروس متقدمة عندما تستخدم كلاسات جاهزة تتيح لك التعامل مع الشبكات (Networks), الواجهات (GUI) و قواعد البيانات (DataBases) بكل سهولة. كما أنك ستراها عندما تعمل على بناء مشاريع كبيرة, تجبرك على إستخدام هذا الأسلوب لتسهيل العمل في المشروع.
الآن سنقوم بتعريف كلاس إسمه A, نوعه abstract, يملك متغير إسمه x, و دالة إسمها print().
بعدها سنقوم ببناء الكلاس Main لتجربة الكود.
المثال الأول
public abstract class A { // إذاً لا يمكن إنشاء كائنات منه ,abstract نوعه A الكلاس
int x;
public void print() {
System.out.println("This is just an example.");
}
}
public class Main {
public static void main(String[] args) {
A a = new A(); // Incompatible Type: abstraction.A is abstract; cannot be instantiated
•سنحصل على النتيجة التالية عند التشغيل.
Uncompilable source code - abstraction.A is abstract; cannot be instantiated
سبب الخطأ هنا أننا حاولنا إنشاء كائن من كلاس نوعه abstract.
الآن سنقوم بإنشاء كلاس جديد إسمه B, يرث من الكلاس A.
بداخل الكلاس Main سننشئ كائن من الكلاس B لنحصل على الأشياء الموجودة في الكلاس A.
المثال الثاني
public abstract class A {
int x;
public void print() {
System.out.println("This is just an example.");
}
}
public class B extends A { // إذاً سيرث كل شيء موجود فيه .A يرث من الكلاس B هنا قلنا أن الكلاس
}
public class Main {
public static void main(String[] args) {
B b = new B(); // B هنا قمنا بإنشاء كائن من الكلاس
b.print(); // A من الكلاس B التي ورثها الكلاس print() هنا قمنا باستدعاء الدالة
b.x = 10; // A من الكلاس B الذي ورثه الكلاس x هنا قمنا بتغيير قيمة المتغير
System.out.println("b.x contain: " + b.x); // x هنا قمنا بعرض قيمة المتغير
}
}
•سنحصل على النتيجة التالية عند التشغيل.
This is just an example. b.x contain: 10
إذاً بما أننا لا نستطيع إنشاء كائن مباشرةً من الكلاس A, قمنا بإنشاء الكلاس B بهدف وراثة الأشياء الموجودة في الكلاس A, و بعدها أنشأنا كائن من الكلاس B و تأكدنا أنه يحتوي على جميع الأشياء الموجودة في الكلاس A.
الآن سنقوم بإضافة دالتين نوعهما abstract في الكلاس A, ثم سنفعل لهما Override في الكلاس B.
بداخل الكلاس Main سننشئ كائن من الكلاس B و سنقوم باستدعاء الدوال الجديدة التي قمنا بإضفاتها.
المثال الثالث
public abstract class A {
int x;
public void print() {
System.out.println("This is just an example.");
}
public abstract void setX(int x); // كل كلاس يرثها Override إذاً يجب أن يفعل لها <-- abstract هنا قمنا بتعريف دالة نوعها
public abstract int getX(); // كل كلاس يرثها Override إذاً يجب أن يفعل لها <-- abstract هنا قمنا بتعريف دالة نوعها
}
public class B extends A { // abstract لأي دالة سيرثها من النوع Override يجب أن يفعل A يرث من الكلاس B بما أن الكلاس
// setX() للدالة Override هنا فعلنا
@Override
public void setX(int x) {
super.x = x;
}
// getX() للدالة Override هنا فعلنا
@Override
public int getX() {
return super.x;
}
}
public class Main {
public static void main(String[] args) {
B b = new B(); // B هنا قمنا بإنشاء كائن من الكلاس
b.print(); // A من الكلاس B التي ورثها الكلاس print() هنا قمنا باستدعاء الدالة
b.setX(55); // setX() عن طريق الدالة A من الكلاس B الذي ورثه الكلاس x هنا قمنا بتغيير قيمة المتغير
System.out.println("b.x contain: " + b.getX()); // getX() عن طريق الدالة x هنا قمنا بعرض قيمة المتغير
}
}
•سنحصل على النتيجة التالية عند التشغيل.
This is just an example. b.x contain: 55
الآن سنقوم بتعريف كلاس إسمه A نوعه abstract, يملك متغير إسمه x, و دالة إسمها print1() نوعها abstract.
بعدها سنقوم بتعريف كلاس إسمه B نوعه abstract يرث من الكلاس A, يملك دالة إسمها print2() نوعها abstract.
بعدها سنقوم بتعريف كلاس إسمه C, يرث من الكلاس B.
في الأخير سنقوم ببناء الكلاس Main لتجربة الكود.
public abstract class A {
int x;
public abstract void print1();
}
public abstract class B extends A {
public abstract void print2();
// print1() أيضاً ورث الدالة B لا تنسى أن الكلاس
}
public class C extends B {
// B التي ورثها من الكلاس abstract لجميع الدوال التي نوعها Override يجب أن يفعل C الكلاس
@Override
public void print1() {
System.out.println("Class C should override the method print1()");
}
@Override
public void print2() {
System.out.println("Class C should override the method print2()");
}
}
public class Main {
public static void main(String[] args) {
C c = new C(); // C هنا قمنا بإنشاء كائن من الكلاس
c.print1(); // Override و فعل لها C التي ورثها الكلاس print1() هنا قمنا باستدعاء الدالة
c.print2(); // Override و فعل لها C التي ورثها الكلاس print2() هنا قمنا باستدعاء الدالة
}
}
•سنحصل على النتيجة التالية عند التشغيل.
Class C should override the method print1() Class C should override the method print2()
الآن سنقوم ببناء كلاس إسمه Person نوعه abstract, يملك أربعة خصائص نوعهم private إسمهم name, gender, brithday و isMarried, و يملك دوال Setter and Getter لهذه الخصائص, و يملك أيضاً دالة إسمها displayInfo() نوعها abstract.
بعدها سنقوم بتعريف كلاس إسمه Student يرث من الكلاس Person و يملك متغير إضافي إسمه specialization.
بعدها سنقوم بتعريف كلاس إسمه Employee يرث من الكلاس Person و يملك متغير إضافي إسمه workPlace.
الفكرة هنا أن أي كلاس سيتم إنشاءه لتمثيل إنسان يجب أن يرث من الكلاس Person الذي يملك الخصائص المشتركة لكل البشر.
في الأخير سنقوم ببناء الكلاس Main لتجربة الكود.
public abstract class Person {
// هنا قمنا بتعريف الخصائص المشتركة لدى جميع البشر
private String name;
private String gender;
private String birthday;
private boolean isMarried;
// هنا قمنا بتعريف الكونستركتور
public Person(String n, String g, String b, boolean i) {
name = n;
gender = g;
birthday = b;
isMarried = i;
}
// Getter هنا قمنا بتعريف دوال الـ
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getBirthday() {
return birthday;
}
public boolean getIsMarried() {
return isMarried;
}
// Setter هنا قمنا بتعريف دوال الـ
public void setName(String n) {
name = n;
}
public void setGender(String g) {
gender = g;
}
public void setBirthday(String b) {
birthday = b;
}
public void setIsMarried(boolean i) {
isMarried = i;
}
// abstract و التي نوعها displayInfo() هنا قمنا بتعريف الدالة
public abstract void displayInfo();
}
public class Student extends Person {
String specialization; // هنا قمنا بتعريف خاصية التخصص و التي يملكها فقط التلاميذ
// هنا قمنا بتعريف الكونستركتور
public Student(String n, String g, String b, boolean i, String s) {
super(n, g, b, i); // Person هنا سيتم إرسال أول أربع قيم إلى كونستركتور الكلاس
specialization = s;
}
// بشكل ملائم للتلامذة displayInfo() للدالة Override هنا فعلنا
@Override
public void displayInfo() {
System.out.println("Name: " + getName());
System.out.println("Gender: " + getGender());
System.out.println("Birthday: " + getBirthday());
System.out.println("Specialization: " + specialization);
System.out.println("---------------------------------");
}
}
public class Employee extends Person {
String workPlace; // هنا قمنا بتعريف خاصية مكان العمل و التي يملكها فقط الموظفون و العمال
// هنا قمنا بتعريف الكونستركتور
public Employee(String n, String g, String b, boolean i, String w) {
super(n, g, b, i); // Person هنا سيتم إرسال أول أربع قيم إلى كونستركتور الكلاس
workPlace = w;
}
// بشكل ملائم للموظفين أو العمال displayInfo() للدالة Override هنا فعلنا
@Override
public void displayInfo() {
System.out.println("Name: " + getName());
System.out.println("Gender: " + getGender());
System.out.println("Birthday: " + getBirthday());
if(getIsMarried() == true) {
System.out.println("is Married: yes");
}
else {
System.out.println("is Married: no");
}
System.out.println("Work place: " + workPlace);
System.out.println("---------------------------------");
}
}
public class Main {
public static void main(String[] args) {
// و هو عبارة عن إنسان له خصائص طالب Student هنا قمنا بإنشاء كائن من الكلاس
Student s = new Student("Mhamad", "Male", "1994", false, "Computer Science");
s.displayInfo();
// و هو عبارة عن إنسان له خصائص موظف أو عامل Employee هنا قمنا بإنشاء كائن من الكلاس
Employee e = new Employee("Rana", "Female", "1986", true, "Al-Iman school");
e.displayInfo();
}
}
•سنحصل على النتيجة التالية عند التشغيل.
Name: Mhamad Gender: Male Birthday: 1994 Specialization: Computer Science --------------------------------- Name: Rana Gender: Female Birthday: 1986 is Married: yes Work place: Al-Iman school ---------------------------------
مفهوم الإنترفيس في جافا
interface هي كلمة محجوزة في جافا, و تكتب إنترفيس في اللغة العربية.
في دروس سابقة رأينا أنه في جافا لا يمكن للكلاس العادي أن يرث من أكثر من كلاس في نفس الوقت لأنه يمكن للكلاس أن يفعل extends لكلاس واحد فقط.
من أجل ذلك عمل مطوروا لغة جافا على إبتكار نوع جديد يشبه الكلاس العادي و يسمح لنا بتطبيق مبدأ تعدد الوراثة الذي يعتبر شيء مهم جداً في لغات البرمجة. هذا النوع الجديد يسمى interface.
يستخدم الإنترفيس كوسيط لتطوير البرامج, و المقصود هنا أن المبرمج يستخدم الإنترفيس إذا أراد جعل برنامجه قابلاً للتطوير بكل مرونة سواءً لأجل نفسه أو من قبل مبرمجين آخرين, فهو يستخدم الإنترفيس لإجبار المبرمجين على اتباع أسلوب محدد يضمن توافق الكودات التي سيكتبها المطورون الآخرون مع كودات البرنامج الأساسية.
إذاً الإنترفيس يستخدم لتجهيز أسلوب يمكن السير عليه لربط الكلاسات بأسلوب سهل, منطقي و مفهوم. سترى قوة الإنترفيس الحقيقية في درس الـ Polymorphism لكننا سنركز في هذا الدرس على طريقة التعامل مع الإنترفيس في جافا.
التعامل مع الإنترفيس في جافا
التعامل مع الإنترفيس يختلف عن التعامل مع الكلاس العادي, و هو يشبه التعامل مع الـ Abstract Class.
فعلياً الإنترفيس يطبق مبدأ الـ Full Abstraction.
الأشياء التي يمكن تعريفها بداخل الإنترفيس
✓دوال لا تملك body, أي Abstract Method.
✓متغيرات مع إعطائهم قيمة بشكل مباشرةً عند تعريفهم. لأن أي متغير تقوم بتعرفه بداخل الإنترفيس يعتبر معرف كـ
public final staticبشكل تلقائي.✓Nested Classes, أي كلاس نوعه
staticبداخل كلاس نوعهstatic.✓Nested Interfaces, أي إنترفيس بداخل إنترفيس.
طريقة تعريف الإنترفيس
الإنترفيس هو في الأساس Full Abstract, لكن لا يجب وضع الكلمة abstract عند تعريفه. و لا يمكن تعريف إنترفيس كـ prviate أو protected لأنه دائماً يعتبر public حتى لو لم تضع كلمة public قبله. كما أنه لا يمكن تعريف الإنترفيس كـ final أو static لأنه تم تصميم الإنترفيس لجعل أي كلاس يرثه يفعل Override للدوال الموجودة فيه.
إذاً لتعريف إنترفيس, أكتب interface ثم ضع له أي إسم تريده.
مثال
interface MyInterface {
}
طريقة تعريف متغيرات بداخل إنترفيس في جافا
متغيرات الإنترفيس تعتبر معرفة كـ public final static حتى لو لم تقم بتعريفها كذلك, الأمر الذي يجعلك مجبراً على إعطاءها قيمة مباشرةً عند تعريفها مع عدم إمكانية تغيير هذه القيمة.
مثال
interface MyInterface {
int X = 1; // حتى و لم نعرفه كذلك public final static يعتبر معرف كـ X المتغير
}
طريقة تعريف دوال بداخل إنترفيس في جافا
دوال الإنترفيس هي في الأساس Abstract Method, إذاً لا حاجة إلى وضع الكلمة abstract عند تعريف أي دالة بداخله. كما أن أي دالة يتم تعريفها بداخله تعتبر public حتى لو لم تعرفها كـ public. و لا يمكن تعريف الدوال فيه كـ prviate أو protected أو final أو static.
مثال
interface MyInterface {
void myMethod(); // حتى و لم نعرفها كذلك public abstract تعتبر معرفة كـ myMethod() الدالة
long myResult(); // حتى و لم نعرفها كذلك public abstract تعتبر معرفة كـ myResult() الدالة
}
شروط الربط بين الكلاس و الإنترفيس
✓لا يمكن إنشاء كائن من إنترفيس.
✓يستطيع الكلاس أن يرث من كلاس واحد, أي يستطيع أن يفعل
extendsلكلاس واحد.✓لا يستطيع الكلاس أن يرث من إنترفيس, أي لا يستطيع أن يفعل
extendsلإنترفيس.✓يستطيع الكلاس تنفيذ إنترفيس أو أكثر, أي يستطيع أن يفعل
implementsلإنترفيس أو أكثر.✓الكلاس الذي ينفذ إنترفيس, يجب أن يفعل Override لجميع الدوال التي ورثها من هذا الإنترفيس .
✓يستطيع الإنترفيس أن يرث من إنترفيس أو أكثر. أي يستطيع الإنترفيس أن يفعل
extendsلإنترفيس أو أكثر.
تنفيذ الإنترفيس في جافا
عند تنفيذ أي إنترفيس, يجب أن تفعل Override لجميع الدوال الموجودة فيه, و يجب تعريفهم كـ public حتى يستطيع أي كائن من هذا الكلاس أن يستخدمهم.
مثال
interface A { // لجميع الدوال الموجودة فيه Override أي كلاس ينفذ هذا الإنترفيس يجب أن يفعل
void print();
}
class B implements A { // A ينفذ الإنترفيس B هنا قلنا أن الكلاس
@Override // public لا تنسى إضافة كلمة .print() للدالة Override مجبور أن يفعل B الكلاس
public void print() {
System.out.println("B should Override this method");
}
}
شروط أساسية عليك اتباعها عند إنشاء إنترفيس
✓لا تستخدم أي Access Modifer عند تعريف إنترفيس.
✓لا تستخدم أي Access Modifer عند تعريف دالة بداخل إنترفيس.
✓بداخل الإنترفيس جميع الدوال يجب أن لا تملك body. و يمكن جعل الدالة ترمي إستثناء.
✓لا يمكن للإنترفيس أن يملك كونستركتور.
في هذا المثال قمنا بتعريف إنترفيس إسمه PhoneNumber يملك دالة إسمها checkNumber() و التي قد ترمي إستثناء في حال مررنا لها رقم يتألف من أكثر من 40 حرف.
ثم قمنا بتعريف كلاس إسمه Phone ينفذ الإنترفيس PhoneNumber.
public interface PhoneNumber {
void checkNumber(String number) throws Exception; // هنا قلنا أن هذه الدالة قد ترمي إستثناء
}
public class Phone implements PhoneNumber { // لجميع الدوال التي ورثها منه Override إذاً يجب أن يفعل PhoneNumber ينفذ الإنترفيس Phone هنا الكلاس
@Override // checkNumber() للدالة Override مجبور أن يفعل Phone الكلاس
public void checkNumber(String number) throws Exception { // هنا قلنا أنها قد ترمي الإستثناء المذكور في الإنترفيس
if ( number.length() > 40 ) { // في حال تم تمرير رقم لها يتألف من أكثر من 40 رقم سيتم رمي إستثناء
throw new Exception("Number is not too big!"); // هذه الرسالة التي ستظهر في حال وقوع إستثناء
}
}
}
الأسباب التي تدفعك إلى استخدام الإنترفيس
✓إذا كنت تنوي بناء كلاس يطبق مفهوم الـ Full Abstraction.
✓لحل مشكلة تعدد الوراثة.
✓لتطبيق مبدأ تعدد الأشكال (Polymorphism).
الفرق بين الكلمتين extends و implements في جافا
✓extendsتعني وراثة, نستخدمها لجعل كلاس يرث من كلاس, أو لجعل إنترفيس يرث من إنترفيس أو أكثر.✓implementsتعني تنفيذ, نستخدمها لجعل كلاس ينفذ إنترفيس أو أكثر.
الصورة التالية توضح لك متى يمكن إستخدام الكلمتين extends و implements.
متى تكون مجبراً على أن تفعل Override و متى لا
في حالة الـ extends:
إذا كان عندك كلاس يرث من كلاس, يكون للـ Subclass الحرية في أن يفعل Override للدوال التي ورثها.
✓إذا كان عندك كلاس يرث من كلاس نوعه
abstract, يكون الـ Subclass مجبراً على أن يفعل Override للدوال المعرفة كـabstract.✓إذا كان عندك إنترفيس يرث من إنترفيس, لا يستطيع الـ SubInterface أن يفعل Override للدوال التي ورثها.
في حالة الـ implements:
✓إذا كان عندك كلاس ينفذ إنترفيس, يكون الـ Subclass مجبراً على أن يفعل Override للدوال التي ورثها.
✓إذا كان عندك كلاس نوعه
abstractينفذ إنترفيس, يكون الـ Subclass له الحرية في أن يفعل Override للدوال التي ورثها.
أشكال تعدد الوراثة في جافا
إذا قام كلاس بتنفيذ أكثر من إنترفيس, أو إذا قام إنترفيس بوراثة أكثر من إنترفيس, تسمى هذه العمليات وراثة متعددة (Multiple Inheritance).
الصورة التالية توضح لك شكل الوراثة المتعددة.
ملاحظة
إذا كان الكلاس ينفذ أكثر من إنترفيس, يجب وضع فاصلة بينهم.
في حال كان الكلاس يرث من كلاس آخر و ينفذ إنترفيس أو أكثر, إفعل extends للكلاس في البداية ثم إفعل implements لأي إنترفيس تريد.
المثال الأول
•هنا قمنا بتعريف إثنين إنترفيس A و B, و قمنا بتعريف كلاس إسمه C و قلنا أن C ينفذ A و B.
interface A { }
interface B { }
class C implements A, B { } // لكل دالة ورثها منهما Override بمعنى أنه يجب أن يفعل B و الإنترفيس A ينفذ الإنترفيس C هنا الكلاس
المثال الثاني
•هنا قمنا بتعريف ثلاثة إنترفيس A, B و C. و قلنا أن C يرث من A و B.
interface A { }
interface B { }
interface C extends A, B { } // B و الإنترفيس A يرث من الإنترفيس C هنا الإنترفيس
المثال الثالث
•هنا قمنا بتعريف إنترفيس A, كلاس B و كلاس C يرث من B و ينفذ A.
interface A { }
class B { }
class C extends B implements A { } // A و ينفذ الإنترفيس B يرث من الكلاس C هنا الكلاس
في حال واجهت صعوبة في فهم الأمثلة السابقة, قمنا بتوضيحها بتفصيل هنا.
مفهوم Nested Interfaces في جافا
يمكنك تعريف إنترفيس بداخل إنترفيس بداخل إنترفيس إلخ.. ويمكنك تنفيذ الإنترفيس الذي تريده منهم بالتحديد متى شئت.
المثال الأول
•هنا قمنا بتعريف إنترفيس A, و بداخله إنترفيس B, و بداخله إنترفيس C.
ثم قمنا بتعريف كلاس D ينفذ A, و كلاس E ينفذ B, و كلاس F ينفذ C.
interface A { // A نكتب A لنصل للإنترفيس
interface B { // A.B نكتب A الموجود بداخل الإنترفيس B لنصل للإنترفيس
interface C { // A.B.C نكتب A الموجود بداخل الإنترفيس B الموجود بداخل الإنترفيس C لنصل للإنترفيس
}
}
}
class D implements A { } // A ينفذ الإنترفيس D هنا الكلاس
class E implements A.B { } // B ينفذ الإنترفيس E هنا الكلاس
class F implements A.B.C { } // C ينفذ الإنترفيس F هنا الكلاس
يمكنك أن تفعل import للإنترفيس و عندها يمكنك أن تكتب إسمه فقط للوصول إليه.
المثال الثاني
•هنا سنفعل import للإنترفيس B و import للإنترفيس C بدل أن نصل إليهم من الإنترفيس A.
import A.B; // لذلك أصبح يمكننا الوصول إليه مباشرةً B هنا قمنا بتحديد المكان الموجود فيه الإنترفيس
import A.B.C; // لذلك أصبح يمكننا الوصول إليه مباشرةً C هنا قمنا بتحديد المكان الموجود فيه الإنترفيس
interface A { // A نكتب A لنصل للإنترفيس
interface B { // B نكتب A الموجود بداخل الإنترفيس B لنصل للإنترفيس
interface C { // C نكتب A الموجود بداخل الإنترفيس B الموجود بداخل الإنترفيس C لنصل للإنترفيس
}
}
}
class D implements A { } // A ينفذ الإنترفيس D هنا الكلاس
class E implements B { } // B ينفذ الإنترفيس E هنا الكلاس
class F implements C { } // C ينفذ الإنترفيس F هنا الكلاس
إنتبه: هنا الإنترفيس B لا يعتبر أنه يرث من الإنترفيس A. كما أن الإنترفيس C لا يعتبر أنه يرث من الإنترفيس B.
مفهوم Tagged Interfaces في جافا
Tagged Interface يقال لها أيضاً Marker Interface, فكرتها تقسيم الـ Interfaces المتشابهين في مجموعات.
لتقسيم الـ Interfaces إلى مجموعات ننشئ إنترفيس فارغ, ثم نجعل كل إنترفيس يشبهه من حيث الفكرة يرث منه.
الآن لنفترض أننا نريد إنشاء مجموعة خاصة للألوان. أول شيء نفعله هو إنشاء إنترفيس فارغ خاص للألوان إسمه Colors.
بعدها نجعل كل إنترفيس له علاقة بالألوان يرث منه, و هكذا سيعتبر المترجم أن كل إنترفيس يرث من Colors هو من النوع Colors.
مثال
interface Colors { }
interface RGB extends Colors { } // Colors أي ينتمي إلى المجموعة Colors يرث من الإنترفيس RGB الإنترفيس
interface PMS extends Colors { } // Colors أي ينتمي إلى المجموعة Colors يرث من الإنترفيس PMS الإنترفيس
interface HEX extends Colors { } // Colors أي ينتمي إلى المجموعة Colors يرث من الإنترفيس HEX الإنترفيس
interface HSL extends Colors { } // Colors أي ينتمي إلى المجموعة Colors يرث من الإنترفيس HSL الإنترفيس
سترى فائدة الـ Tagged Interface في الدرس التالي.
المثال الأول
في هذا المثال قمنا بتعريف إثنين إنترفيس A و B:
الإنترفيس
Aيملك دالة إسمهاprintA().الإنترفيس
Bيملك دالة إسمهاprintB().
ثم قمنا بتعريف كلاس إسمه C و قلنا أن C ينفذ A و B.
public interface A {
void printA();
}
public interface B {
void printB();
}
public class C implements A, B { // لجميع الدوال التي ورثها Override إذاً يجب أن يفعل B و الإنترفيس A ينفذ الإنترفيس C هنا الكلاس
@Override // printA() للدالة Override مجبور أن يفعل C الكلاس
void printA() {
System.out.println("C should Override the method printA()");
}
@Override // printB() للدالة Override مجبور أن يفعل C الكلاس
void printB() {
System.out.println("C should Override the method printB()");
}
}
المثال الثاني
في هذا المثال قمنا بتعريف إنترفيس A يملك دالة إسمها printA().
و إنترفيس B يرث من الإنترفيس A و يملك دالة إسمها printB().
ثم قمنا بتعريف كلاس إسمه C يطبق الإنترفيس B, و بالتالي عليه أن يفعل Override لجميع الدوال التي ورثها.
public interface A {
void printA();
}
public interface B extends A {
void printB();
}
public class C implements B { // printB() و printA() للدالتين Override إذاً يجب أن يفعل .B و الذي بدوره يرث من الإنترفيس B يطبق من الإنترفيس C هنا الكلاس
@Override // printA() للدالة Override مجبور أن يفعل C الكلاس
void printA() {
System.out.println("C should Override the method printA()");
}
@Override // printB() للدالة Override مجبور أن يفعل C الكلاس
void printB() {
System.out.println("C should Override the method printB()");
}
}
المثال الثالث
في هذا المثال قمنا بتعريف إنترفيس A يملك دالة إسمها printA().
و كلاس B يملك دالة إسمها printB().
ثم قمنا بتعريف كلاس إسمه C يرث من B و ينفذ A.
public interface A {
void printA();
}
public class B {
void printB() {
System.out.println("C not need to Override the method printB()");
}
}
public class C extends B implements A { // A و ينفذ الإنترفيس B يرث من الكلاس C هنا الكلاس
@Override // printA() للدالة Override مجبور أن يفعل C الكلاس
void printA() {
System.out.println("C should Override the method printA()");
}
}