كما تعلم، كل شيء في Java يتكون من كائنات، والكائنات لها حالة (حقول) وسلوك (محدد بالطرق). سلوك الفصل هو ما يمكن أن يربطه بالفئات الأخرى. يمكن أن يكون للسلوك خصائص مختلفة، وفي بعض الأحيان قد يكون من الملائم أكثر نقله خارج الفصل، خاصة عندما يتعلق الأمر بالتفاعل مع العالم الخارجي. تمامًا مثلما يكون جهاز التحكم عن بعد الخاص بالتلفزيون خارج "الصندوق" نفسه. جهاز التحكم عن بعد هو واجهة لتفاعل المستخدم مع وظائف التلفزيون. على سبيل المثال، يمكنك تخيل فصل دراسي يقوم بتنفيذ طائرة أو مروحية مجردة. الكائنات من كلا الفئتين، مثل معظم الطيور، يمكنها الطيران، وكلها تفعل ذلك بشكل مختلف. ربما يكون من المفيد نقل هذه الميزة إلى كيان منفصل، وسيتم توريث جميع "النشرات" المحتملة من هذا الكيان؟ إذا كنت معتادًا على الفئات المجردة، فيمكنك فقط إنشاء فئة مجردة Flyable و"وراثة" فئات Copter وPlane منها. ومع ذلك، ماذا لو كان هناك العديد من هذه الخصائص؟ على سبيل المثال، يمكن للطائرات والمروحيات الطيران، ولكن يمكنها أيضًا السفر على الأرض. حتى لو قمنا بإنشاء فئة الركوب، لم يعد بإمكاننا تعيين Copter وPlane لها. بعد كل شيء، كل فئة جافا لديها فئة أصل واحدة فقط. يؤدي استخدام الواجهات بلغة Java إلى حل هذه المشكلة جزئيًا. تحدد الواجهات في Java بعض الوظائف التي لا تحتوي على تطبيق محدد، والتي يتم تنفيذها بعد ذلك بواسطة الفئات التي تستخدم هذه الواجهات. ويمكن لفئة واحدة تنفيذ العديد من الواجهات. في الواقع، من خلال تنفيذ واجهة في Java، نعلن أن فصلنا يمكنه فعل شيء ما، ونبلغ عن سلوكه. لقد قمنا بالفعل بالتنفيذ الملموس للسلوك في الفصل. لذا. تقلع الطائرة والمروحية بشكل مختلف: تحتاج الطائرة إلى مدرج، بينما تقلع المروحية عموديًا عادةً. من الأفضل تنفيذ هذه التفاصيل داخل الفصل.
واجهات في جافا
لتحديد واجهة بلغة Java، يتم استخدام الكلمة الأساسية للواجهة. على سبيل المثال:interface Voice {
void talk();
}
الواجهة أعلاه تسمى Voice . قد تحدد الواجهة في Java ثوابت وأساليب، والتي قد تحتوي أو لا تحتوي على تطبيقات. عادةً، لا تحتوي أساليب الواجهة على تطبيق، تمامًا كما في هذا المثال. تشبه الأساليب الموجودة في الواجهات دون التنفيذ الأساليب المجردة للفئات المجردة. عادةً لا تحتوي طرق الواجهة على معدّلات وصول. ومع ذلك، يكون الوصول عامًا بشكل افتراضي لأن الغرض من الواجهة هو تحديد وظيفة تنفيذ الفصل. لذلك، يجب أن تكون جميع الوظائف مفتوحة للتنفيذ. لتنفيذ واجهة، استخدم الكلمة الأساسية للتنفيذ أثناء الإعلان عن فصلك. علاوة على ذلك، إذا كانت الواجهة تحتوي على طريقة بدون تطبيق، فيجب تنفيذ هذه الطريقة في فئة التنفيذ.
public class Duck implements Voice {
@Override
public void voice() {
System.out.println("Quack");
}
}
مثال على رمز الواجهة
لنأخذ مثالا أكثر اكتمالا. كل حيوان (حسنًا، كل حيوان تقريبًا) لديه القدرة على إصدار الأصوات. لنقم بإنشاء واجهة Java Voice لهذه الحالة. لديها طريقة talk() بدون تنفيذ.public interface Voice {
void talk();
}
الآن يجب أن يكون لدى كافة الفئات التي تدعم الواجهة الصوتية تطبيق لطريقة talk() . لنقم بإنشاء فئتين — Cat و Dog ونشير إلى أنهما ينفذان الواجهة الصوتية . في هذه الحالة، إذا لم تقم بتنفيذ فصل دراسي فيه، فلن يعمل البرنامج. طرق التنفيذ بسيطة للغاية. عند استدعاء طريقة talk() لكائن من فئة Cat ، سيتم عرض النص المكافئ لمواء على الشاشة، وفي حالة فئة Dog ، سيتم عرض النباح. سنقوم أيضًا بإضافة الحروف والمستوطنين والمنشئ إلى الفئات.
public class Cat implements Voice {
String name;
String breed;
int year;
public Cat(String name, String breed, int year) {
this.name = name;
this.breed = breed;
this.year = year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public void talk() {
System.out.println("meow...");
}
}
public class Dog implements Voice {
String name;
String color;
int year;
public Dog(String name, String color, int year) {
this.name = name;
this.color = color;
this.year = year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public void talk() {
System.out.println("WOF WOF");
}
}
في الواقع، تطبيقاتنا للطبقات والأساليب متشابهة جدًا. لنقم بإنشاء فئة أخرى، Parrot ، بدعم صوتي . ستعمل طريقة talk() فقط بشكل مختلف: سيقوم المستخدم بإدخال سلسلة في وحدة التحكم، وسيقوم الببغاء "بتكرارها" باستخدام طريقة talk() .
import java.util.Scanner;
public class Parrot implements Voice {
String name;
String color;
int year;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public void talk() {
Scanner scanner = new Scanner(System.in);
System.out.println("WHat should I repeat after you?...");
String s = scanner.nextLine();
System.out.println(s);
}
}
الآن لنقم بإنشاء فئة اختبار ونرى النتيجة التي سينتجها البرنامج إذا قمنا باستدعاء طريقة talk() لكائنات فئات Cat و Dog و Parrot بدورها.
public class InterfaceDemo {
public static void main(String[] args) {
Cat cat = new Cat ("Mewie", "Siam" ,2021);
cat.talk();
Dog dog = new Dog("Snoopy", "White and black", 2020);
dog.talk();
Parrot parrot = new Parrot();
parrot.talk();
}
}
الإخراج أدناه. النص الأخضر هو المستخدم الوحيد المطبوع في وحدة التحكم.
مواء... ووف ووف ماذا يجب أن أكرر بعدك؟... أنا طائر ثرثار وذكي للغاية أنا طائر ثرثار وذكي للغاية
الأساليب الافتراضية
قبل إصدار JDK 8 عند تنفيذ واجهة في Java، كان علينا تنفيذ جميع أساليبها في الفصل الدراسي. في الوقت نفسه، يمكن أن تحتوي واجهة Java نفسها على تعريفات الطريقة فقط دون تنفيذ محدد. يضيف JDK 8 وظائف جديدة — الطرق الافتراضية. الآن، لا يمكن لواجهات Java أن تحتوي على تعريفات للطرق فحسب، بل أيضًا على التطبيقات الافتراضية. يتم استخدامها إذا كان الفصل يطبق الواجهة ولكنه لا ينفذ الطريقة. على سبيل المثال، لنغير طريقة talk() في واجهة الصوت إلى الطريقة الافتراضية. سنكتب أيضًا فئة Duck جديدة تدعم الصوت ولا تحتوي على تطبيق لطريقة التحدث .public interface Voice {
default void talk() {
System.out.println("I can talk...");
}
}
public class Duck implements Voice {
public void moveForward() {
System.out.println(" Quack, I am moving forward...");
}
public void TurnRight(){
System.out.println("I am turning right...");
}
public void TurnLeft(){
System.out.println("I am turning left...");
}
public void Stop() {
System.out.println("Quack. I am relaxing on the surface of the water...");
}
public void fly(){
System.out.println("I am flying!!!");
}
}
الآن دعونا نغير فئة الاختبار لدينا قليلاً.
public class InterfaceDemo {
public static void main(String[] args) {
Cat cat = new Cat ("Mewie", "Siam" ,2021);
cat.talk();
Dog dog = new Dog("Snoopy", "White and black", 2020);
dog.talk();
Duck duck = new Duck();
duck.talk();
}
}
الإخراج هنا:
مواء... ووف ووف أستطيع التحدث...
يرى؟ في كائنات فئتي Dog و Cat ، يتم استدعاء الطريقة المتجاوزة talk() ، ولكن في كائن من فئة Duck ، يتم استدعاء الطريقة الافتراضية من الواجهة. وبالتالي، فإن الطريقة الافتراضية هي مجرد طريقة بدون معدلات ويتم تمييزها بالكلمة الأساسية الافتراضية. لا يتعين علينا تنفيذ الطريقة الافتراضية في الفصل الذي ينفذ الواجهة، ولكن يمكننا تجاوزها.
الأساليب الثابتة
نظرًا لأن الأساليب الثابتة لـ JDK 8 متوفرة في واجهات Java، فهي تشبه أساليب الفصل:interface Voice {
void talk();
static void check(){
System.out.println("checked...");
}
}
للإشارة إلى طريقة ثابتة لواجهة ما، تمامًا كما في حالة الفئات، اكتب اسم الواجهة والطريقة:
public static void main(String[] args) {
Voice.check();
}
التنفيذ المتعدد للواجهات
إذا كنا بحاجة إلى تطبيق عدة واجهات في فئة Java، فسيتم إدراجها جميعها بفاصلة بعد تنفيذ الكلمة :public class Duck implements Swimmable, Flyable, Voice {
public void moveForward() {
System.out.println(" Quack, I am moving forward...");
}
public void TurnRight(){
System.out.println("I am turning right...");
}
public void TurnLeft(){
System.out.println("I am turning left...");
}
public void Stop() {
System.out.println("Quack. I am relaxing on the surface of the water...");
}
public void fly(){
System.out.println("I am flying!!!");
}
}
GO TO FULL VERSION