264 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			264 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| title: Interfaces
 | ||
| localeTitle: واجهات
 | ||
| ---
 | ||
| # واجهات
 | ||
| 
 | ||
| واجهة في جافا قليلا مثل فئة، ولكن مع فارق كبير: و `interface` يمكن أن يكون _فقط_ تواقيع طريقة والحقول والطرق الافتراضية. منذ Java 8 ، يمكنك أيضًا إنشاء [طرق افتراضية](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html) . في الجزء التالي ، يمكنك مشاهدة مثال على الواجهة:
 | ||
| 
 | ||
| ```java
 | ||
| public interface Vehicle {
 | ||
|     public String licensePlate = "";
 | ||
|     public float maxVel
 | ||
|     public void start();
 | ||
|     public void stop();
 | ||
|     default void blowHorn(){
 | ||
|       System.out.println("Blowing horn");
 | ||
|    }
 | ||
| }
 | ||
| ``` 
 | ||
| 
 | ||
| تحتوي الواجهة أعلاه على حقلين وطريقتين وطريقة افتراضية. وحدها ، ليست ذات فائدة كبيرة ، ولكنها تستخدم عادة مع الفصول. ماذا؟ بسيطة ، عليك أن تتأكد من أن بعض الصف يقوم `implements` .
 | ||
| 
 | ||
| ```java
 | ||
| public class Car implements Vehicle {
 | ||
|     public void start() {
 | ||
|         System.out.println("starting engine...");
 | ||
|     }
 | ||
|     public void stop() {
 | ||
|         System.out.println("stopping engine...");
 | ||
|     }
 | ||
| }
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CItd/0)
 | ||
| 
 | ||
| الآن ، هناك **قاعدة أساسية** : يجب على الفئة تنفيذ **كافة** الطرق في الواجهة. يجب أن تحتوي الطرق _على نفس_ التوقيع _بالضبط_ (الاسم والمعلمات والاستثناءات) كما هو موضح في الواجهة. الفئة _لا_ تحتاج إلى إعلان الحقول رغم ذلك ، فقط الطرق.
 | ||
| 
 | ||
| ## مثيلات واجهة
 | ||
| 
 | ||
| بمجرد إنشاء فئة Java تقوم `implements` أي واجهة ، يمكن الإشارة إلى مثيل الكائن كمثيل للواجهة. هذا المفهوم مشابه لمبدأ إنشاء الوراثة.
 | ||
| 
 | ||
| ```java
 | ||
| // following our previous example
 | ||
| 
 | ||
| Vehicle tesla = new Car();
 | ||
| 
 | ||
| tesla.start(); // starting engine ...
 | ||
| ``` 
 | ||
| 
 | ||
| **لا يمكن أن** تحتوي واجهة على أساليب منشئ ، لذلك **لا يمكنك** إنشاء مثيل لواجهة بنفسها. يجب إنشاء مثيل لفئة معينة تقوم بتطبيق واجهة للرجوع إليها. فكر في الواجهات على أنها نموذج عقد فارغ ، أو نموذج.
 | ||
| 
 | ||
| ما الذي يمكنك القيام به مع هذه الميزة؟ تعدد الأشكال! يمكنك استخدام الواجهات فقط للإشارة إلى مثيلات الكائن!
 | ||
| 
 | ||
| ```java
 | ||
| class Truck implements Vehicle {
 | ||
|     public void start() {
 | ||
|         System.out.println("starting truck engine...");
 | ||
|     }
 | ||
|     public void stop() {
 | ||
|         System.out.println("stopping truck engine...");
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| class Starter {
 | ||
|     // static method, can be called without instantiating the class
 | ||
|     public static void startEngine(Vehicle vehicle) {
 | ||
|         vehicle.start();
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| Vehicle tesla = new Car();
 | ||
| Vehicle tata = new Truck();
 | ||
| 
 | ||
| Starter.startEngine(tesla); // starting engine ...
 | ||
| Starter.startEngine(tata); // starting truck engine ...
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CItm/0)
 | ||
| 
 | ||
| ## ولكن ماذا عن واجهات متعددة؟
 | ||
| 
 | ||
| نعم ، يمكنك تنفيذ واجهات متعددة في فصل واحد. أثناء [تواجدك](//forum.freecodecamp.com/t/java-docs-inheritance) في [التوارث](//forum.freecodecamp.com/t/java-docs-inheritance) داخل الصفوف ، تم تقييدك في فئة واحدة فقط ، يمكنك هنا توسيع أي عدد من الواجهات. ولكن لا ننسى تنفيذ _جميع_ أساليب جميع واجهات ، وإلا سوف تفشل التجميع!
 | ||
| 
 | ||
| ```java
 | ||
| public interface GPS {
 | ||
|     public void getCoordinates();
 | ||
| }
 | ||
| 
 | ||
| public interface Radio {
 | ||
|     public void startRadio();
 | ||
|     public void stopRadio();
 | ||
| }
 | ||
| 
 | ||
| public class Smartphone implements GPS,Radio {
 | ||
|     public void getCoordinates() {
 | ||
|         // return some coordinates
 | ||
|     }
 | ||
|     public void startRadio() {
 | ||
|       // start Radio
 | ||
|     }
 | ||
|     public void stopRadio() {
 | ||
|         // stop Radio
 | ||
|     }
 | ||
| }
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CIto/0)
 | ||
| 
 | ||
| ## بعض ميزات واجهات
 | ||
| 
 | ||
| *   يمكنك وضع المتغيرات داخل واجهة ، على الرغم من أنه لن يكون قرارًا معقولًا لأن الفئات غير مرتبطة بالمتغير نفسه. باختصار ، تجنب وضع المتغيرات!
 | ||
| *   تكون جميع المتغيرات والطرق في الواجهة عامة ، حتى إذا تركت الكلمة الرئيسية `public` .
 | ||
| *   لا يمكن للواجهة تحديد تنفيذ طريقة معينة. ما يصل إلى فئات للقيام بذلك. على الرغم من وجود استثناء حديث (انظر أدناه).
 | ||
| *   إذا قامت فئة بتطبيق واجهات متعددة ، فهناك احتمال بعيد لتداخل توقيع الأسلوب. بما أن Java لا تسمح بطرق متعددة من نفس التوقيع بالضبط ، فقد يؤدي هذا إلى حدوث مشكلات. انظر [هذا السؤال](http://stackoverflow.com/questions/2598009/method-name-collision-in-interface-implementation-java) لمزيد من المعلومات.
 | ||
| 
 | ||
| ## طرق الواجهة الافتراضية
 | ||
| 
 | ||
| قبل Java 8 ، لم يكن لدينا طريقة لتوجيه واجهة لتطبيق طريقة معينة. هذا يؤدي إلى الكثير من الارتباك وفواصل التعليمات البرمجية إذا تم تغيير تعريف واجهة فجأة.
 | ||
| 
 | ||
| لنفترض أنك كتبت مكتبة مفتوحة المصدر تحتوي على واجهة. لنفترض أن عملاءك ، أي جميع المطورين تقريبًا في جميع أنحاء العالم ، يستخدمونها بكثافة ويسعدون. الآن كان عليك ترقية المكتبة بإضافة تعريف أسلوب جديد إلى الواجهة لدعم ميزة جديدة. ولكن هذا من شأنه أن يكسر _جميع عمليات_ البناء لأن كل الطبقات التي تقوم بتنفيذ هذه الواجهة يجب أن تتغير الآن. يا لها من كارثة!
 | ||
| 
 | ||
| لحسن الحظ ، توفر لك Java 8 الآن الطرق `default` للواجهات. _يمكن أن_ تحتوي الطريقة `default` على التنفيذ الخاص بها _مباشرة_ داخل الواجهة! لذا ، إذا لم يقم تطبيق Class بتنفيذ طريقة افتراضية ، فسيأخذ المترجم التنفيذ المذكور داخل الواجهة. جميل أليس كذلك؟ لذلك في مكتبتك ، يمكنك إضافة أي عدد من الطرق الافتراضية في واجهات دون الخوف من كسر أي شيء!
 | ||
| 
 | ||
| ```java
 | ||
| public interface GPS {
 | ||
|     public void getCoordinates();
 | ||
|     default public void getRoughCoordinates() {
 | ||
|         // implementation to return coordinates from rough sources
 | ||
|         // such as wifi & mobile
 | ||
|         System.out.println("Fetching rough coordinates...");
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| public interface Radio {
 | ||
|     public void startRadio();
 | ||
|     public void stopRadio();
 | ||
| }
 | ||
| 
 | ||
| public class Smartphone implements GPS,Radio {
 | ||
|     public void getCoordinates() {
 | ||
|         // return some coordinates
 | ||
|     }
 | ||
|     public void startRadio() {
 | ||
|       // start Radio
 | ||
|     }
 | ||
|     public void stopRadio() {
 | ||
|         // stop Radio
 | ||
|     }
 | ||
| 
 | ||
|     // no implementation of getRoughCoordinates()
 | ||
| }
 | ||
| 
 | ||
| Smartphone motoG = new Smartphone();
 | ||
| motog.getRoughCoordinates(); // Fetching rough coordinates...
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CItp/0)
 | ||
| 
 | ||
| ### ولكن ، ماذا يحدث إذا كان للواجهتين نفس توقيع الطريقة؟
 | ||
| 
 | ||
| سؤال رائع. في هذه الحالة ، إذا لم تقدم التطبيق في الصف ، فسوف يتم خلط المترجم الضعيف ويفشل ببساطة! يجب عليك توفير تنفيذ طريقة افتراضية داخل الفئة أيضًا. هناك أيضًا طريقة رائعة تستخدم ميزة `super` للاتصال بأي تطبيق تريده:
 | ||
| 
 | ||
| ```java
 | ||
| public interface Radio {
 | ||
|     // public void startRadio();
 | ||
|     // public void stopRadio();
 | ||
| 
 | ||
|     default public void next() {
 | ||
|         System.out.println("Next from Radio");
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| public interface MusicPlayer {
 | ||
|     // public void start();
 | ||
|     // public void pause();
 | ||
|     // public void stop();
 | ||
| 
 | ||
|     default public void next() {
 | ||
|         System.out.println("Next from MusicPlayer");
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| public class Smartphone implements Radio, MusicPlayer {
 | ||
|     public void next() {
 | ||
|         // Suppose you want to call MusicPlayer next
 | ||
|         MusicPlayer.super.next();
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| Smartphone motoG = new Smartphone();
 | ||
| motoG.next(); // Next from MusicPlayer
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CIts/0)
 | ||
| 
 | ||
| ## طرق ثابتة في واجهات
 | ||
| 
 | ||
| جديد أيضا إلى Java 8 هو القدرة على إضافة أساليب ثابتة إلى واجهات. تتشابه الطرق الثابتة في الواجهات تقريبًا مع الطرق الثابتة في الفصول الخرسانية. الاختلاف الكبير الوحيد هو أن الأساليب `static` غير موروثة في الفئات التي تقوم بتطبيق الواجهة. وهذا يعني أنه يتم الإشارة إلى الواجهة عند استدعاء الأسلوب الثابت وليس الفئة التي تقوم بتطبيقه.
 | ||
| 
 | ||
|  `interface MusicPlayer { 
 | ||
|   public static void commercial(String sponsor) { 
 | ||
|     System.out.println("Now for a message brought to you by " + sponsor); 
 | ||
|   } 
 | ||
|  
 | ||
|   public void play(); 
 | ||
|  } 
 | ||
|  
 | ||
|  
 | ||
|  class Smartphone implements MusicPlayer { 
 | ||
|     public void play() { 
 | ||
|         System.out.println("Playing from smartphone"); 
 | ||
|     } 
 | ||
|  } 
 | ||
|  
 | ||
|  class Main { 
 | ||
|   public static void main(String[] args) { 
 | ||
|     Smartphone motoG = new Smartphone(); 
 | ||
|     MusicPlayer.commercial("Motorola"); // Called on interface not on implementing class 
 | ||
|     // motoG.commercial("Motorola"); // This would cause a compilation error 
 | ||
|   } 
 | ||
|  } 
 | ||
| ` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CIts/9)
 | ||
| 
 | ||
| ## وراثة واجهة
 | ||
| 
 | ||
| من الممكن أيضًا في Java لواجهة _ترث_ واجهة أخرى ، باستخدام ، تفكر في ذلك ، `extends` الكلمة الرئيسية:
 | ||
| 
 | ||
| ```java
 | ||
| public interface Player {
 | ||
|     public void start();
 | ||
|     public void pause();
 | ||
|     public void stop();
 | ||
| }
 | ||
| 
 | ||
| public interface MusicPlayer extends Player {
 | ||
|     default public void next() {
 | ||
|         System.out.println("Next from MusicPlayer");
 | ||
|     }
 | ||
| }
 | ||
| ``` 
 | ||
| 
 | ||
| هذا يعني ، أن تطبيق Class `MusicPlayer` Interface (واجهة `MusicPlayer` يجب أن يقوم بتنفيذ _جميع_ أساليب `MusicPlayer` بالإضافة إلى `Player` :
 | ||
| 
 | ||
| ```java
 | ||
| public class SmartPhone implements MusicPlayer {
 | ||
|     public void start() {
 | ||
|         System.out.println("start");
 | ||
|     }
 | ||
|     public void stop() {
 | ||
|         System.out.println("stop");
 | ||
|     }
 | ||
|     public void pause() {
 | ||
|         System.out.println("pause");
 | ||
|     }
 | ||
| }
 | ||
| ``` 
 | ||
| 
 | ||
|  [تشغيل الكود](https://repl.it/CIty/0)
 | ||
| 
 | ||
| عفوًا ، هل نسيت `next()` ؟ انظر ، لأنه كان طريقة `default` ، لم يكن لدي لتوفير التنفيذ على الإطلاق. (لن يعمل لـ JDK <8)
 | ||
| 
 | ||
| لذلك ، الآن لديك فهم جيد للواجهات! اذهب لمعرفة المزيد عن "الطبقات المستخلصة" لتعرف كيف تقدم لك جافا طريقة أخرى لتعريف العقود. |