تغييرات واجهة Java 8 – الطريقة الثابتة، الطريقة الافتراضية

Java 8 تتضمن تغييرات في واجهة البرمجة تشمل طرقًا ثابتة وطرقًا افتراضية في الواجهات. قبل Java 8 ، كان يمكننا فقط إعلان الطرق في الواجهات. ولكن ابتداءً من Java 8 ، يمكننا إضافة طرق افتراضية و طرق ثابتة في الواجهات.

واجهة Java 8

تصميم الواجهات كان دائمًا مهمة صعبة لأنه إذا كنا نريد إضافة طرق إضافية في الواجهات ، فسيتعين تغيير جميع الفئات التي تنفذها. كلما كبرت الواجهة ، قد يزداد عدد الفئات التي تنفذها إلى حد لا يمكن فيه توسيع الواجهات. لهذا السبب ، عند تصميم التطبيق ، يقدم معظم الأطُر أحيانًا فئة تنفيذ أساسية ، ثم نمتد منها ونعدل الطرق التي تنطبق على تطبيقنا. دعونا نلقي نظرة على طرق الواجهة الافتراضية وطرق الواجهة الثابتة وسبب إدخالها في تغييرات واجهة Java 8.

الطريقة الافتراضية في واجهة Java

لإنشاء طريقة افتراضية في واجهة جافا، نحتاج إلى استخدام الكلمة الرئيسية “default” مع توقيع الطريقة. على سبيل المثال،

package com.journaldev.java8.defaultmethod;

public interface Interface1 {

	void method1(String str);
	
	default void log(String str){
		System.out.println("I1 logging::"+str);
	}
}

لاحظ أن log(String str) هي الطريقة الافتراضية في الواجهة Interface1. الآن عندما تقوم فئة بتنفيذ Interface1، ليس من الضروري توفير تنفيذ للطرق الافتراضية للواجهة. ستساعدنا هذه الميزة في توسيع الواجهات بطرق إضافية، كل ما نحتاجه هو توفير تنفيذ افتراضي. لنفترض أن لدينا واجهة أخرى بها الطرق التالية:

package com.journaldev.java8.defaultmethod;

public interface Interface2 {

	void method2();
	
	default void log(String str){
		System.out.println("I2 logging::"+str);
	}

}

نحن نعلم أن جافا لا تسمح لنا بتمديد فئات متعددة لأن ذلك سيؤدي إلى “مشكلة الماس” حيث لا يمكن للمترجم أن يقرر أي طريقة فئة أساسية يجب استخدامها. مع الطرق الافتراضية، ستحدث مشكلة الماس أيضًا للواجهات. لأنه إذا كانت فئة تنفيذ كلاً من Interface1 وInterface2 ولم تنفذ الطريقة الافتراضية المشتركة، فإن المترجم لا يمكنه تحديد أي واحدة يجب اختيارها. تمديد الواجهات متعددة هو جزء أساسي من جافا، ستجده في فئات جافا الأساسية وكذلك في معظم تطبيقات الشركات والإطارات. لذا للتأكد من عدم حدوث هذه المشكلة في الواجهات، تم تحديد توفير تنفيذ للطرق الافتراضية المشتركة للواجهات كمتطلب إلزامي. لذا إذا كانت فئة تنفيذ كلاً من الواجهات أعلاه، فستضطر إلى توفير تنفيذ للطريقة log() وإلا سيقوم المترجم بإلقاء خطأ في وقت الترجمة. فئة بسيطة تنفذ كلاً من Interface1 وInterface2 ستكون:

package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

	@Override
	public void method2() {
	}

	@Override
	public void method1(String str) {
	}

	@Override
	public void log(String str){
		System.out.println("MyClass logging::"+str);
		Interface1.print("abc");
	}
}

نقاط هامة حول طرق الواجهة الافتراضية في جافا:

  1. سيساعدنا طرق الافتراضية في واجهة Java في تمديد الواجهات دون الخوف من كسر فئات التنفيذ.
  2. طرق الافتراضية في واجهة Java قد جسرت الفروقات بين الواجهات والفئات المجردة.
  3. ستساعد طرق الافتراضية في واجهة Java 8 في تجنب فئات المساعدة، مثل يمكن توفير جميع طرق فئة الCollections في الواجهات نفسها.
  4. ستساعد طرق الافتراضية في واجهة Java في إزالة فئات التنفيذ الأساسية، يمكننا توفير تنفيذ افتراضي ويمكن لفئات التنفيذ اختيار أيها يجب تجاوزه.
  5. أحد الأسباب الرئيسية لإدخال الطرق الافتراضية في الواجهات هو تعزيز واجهات الCollections API في Java 8 لدعم التعبيرات لامبدا.
  6. إذا كانت لدى أي فئة في التسلسل طريقة بنفس التوقيع، فإن الطرق الافتراضية تصبح غير مهمة. لا يمكن للطريقة الافتراضية تجاوز طريقة من java.lang.Object. السبب بسيط جدًا، لأن Object هو الفئة الأساسية لجميع فئات Java. لذا حتى لو كانت طرق فئة Object معرفة كطرق افتراضية في الواجهات، فإنها ستكون غير مفيدة لأن طريقة فئة Object ستستخدم دائمًا. لهذا السبب، لتجنب الالتباس، لا يمكننا أن نمتلك طرق افتراضية تعترض طرق فئة Object.
  7. تشار إلى طرق الافتراضية في واجهة Java أيضًا باسم طرق الدفاع أو طرق التمديد الافتراضي.

طريقة واجهة Java الثابتة

الواجهة الثابتة للواجهة جافا مشابهة للطريقة الافتراضية باستثناء أننا لا يمكننا تجاوزها في فئات التنفيذ. تساعدنا هذه الميزة في تجنب النتائج غير المرغوب فيها في حالة التنفيذ الضعيف في فئات التنفيذ. دعونا نلقي نظرة على هذا بمثال بسيط.

package com.journaldev.java8.staticmethod;

public interface MyData {

	default void print(String str) {
		if (!isNull(str))
			System.out.println("MyData Print::" + str);
	}

	static boolean isNull(String str) {
		System.out.println("Interface Null Check");

		return str == null ? true : "".equals(str) ? true : false;
	}
}

الآن دعونا نرى فئة تنفيذ تحتوي على طريقة isNull() بتنفيذ ضعيف.

package com.journaldev.java8.staticmethod;

public class MyDataImpl implements MyData {

	public boolean isNull(String str) {
		System.out.println("Impl Null Check");

		return str == null ? true : false;
	}
	
	public static void main(String args[]){
		MyDataImpl obj = new MyDataImpl();
		obj.print("");
		obj.isNull("abc");
	}
}

يرجى ملاحظة أن isNull(String str) هي طريقة فئة بسيطة، ليست تجاوز لطريقة الواجهة. على سبيل المثال، إذا قمنا بإضافة @Override annotation إلى طريقة isNull()، سيؤدي ذلك إلى خطأ المترجم. الآن عند تشغيل التطبيق، نحصل على الإخراج التالي.

Interface Null Check
Impl Null Check

إذا قمنا بتحويل الطريقة الثابتة للواجهة من ثابتة إلى افتراضية، سنحصل على الإخراج التالي.

Impl Null Check
MyData Print::
Impl Null Check

الطريقة الثابتة للواجهة جافا مرئية لطرق الواجهة فقط، إذا قمنا بإزالة طريقة isNull() من فئة MyDataImpl، لن نكون قادرين على استخدامها لكائن MyDataImpl. ومع ذلك، مثل الطرق الثابتة الأخرى، يمكننا استخدام الطرق الثابتة للواجهة باستخدام اسم الفئة. على سبيل المثال، سيكون البيان التالي صحيحًا:

boolean result = MyData.isNull("abc");

نقاط مهمة حول الطريقة الثابتة للواجهة جافا:

  1. الطريقة الثابتة للواجهة جافا جزء من الواجهة، لا يمكننا استخدامها لأجل كائنات فئة التنفيذ.
  2. الطرق الثابتة للواجهة جافا جيدة لتوفير الطرق المساعدة، على سبيل المثال التحقق من القيمة الفارغة، فرز المجموعات وما إلى ذلك.
  3. الواجهة الثابتة في جافا تساعدنا في توفير الأمان عن طريق عدم السماح للفئات التنفيذية بتجاوزها.
  4. لا يمكننا تعريف طريقة واجهة ثابتة لأساليب فئة Object ، سنحصل على خطأ مترجم يقول “لا يمكن لهذه الطريقة الثابتة إخفاء الطريقة النمطية من Object”. هذا لأنه غير مسموح به في جافا ، حيث أن Object هو الفئة الأساسية لجميع الفئات ولا يمكننا أن نمتلك طريقة ثابتة على مستوى الفئة وطريقة نموذجية أخرى بنفس التوقيع.
  5. يمكننا استخدام الواجهات الثابتة في جافا لإزالة فئات الأدوات مثل Collections ونقل جميع طرقها الثابتة إلى الواجهة المقابلة ، وسيكون من السهل العثور عليها واستخدامها.

واجهات جافا الوظيفية

قبل أن أختتم المنشور، أود أن أقدم مقدمة موجزة حول الواجهات الوظيفية. الواجهة التي تحتوي على دقيقة واحدة مجردة تعرف باسم واجهة وظيفية. تم إدخال تعليق جديد @FunctionalInterface لتمييز الواجهة كواجهة وظيفية. التعليق @FunctionalInterface هو وسيلة لتجنب إضافة دوال مجردة عن طريق الخطأ في الواجهات الوظيفية. اختياري ولكن من الجيد استخدامه. الواجهات الوظيفية هي ميزة مرغوبة منذ فترة طويلة ومطلوبة جدًا في جافا 8 لأنها تمكننا من استخدام تعبيرات لامبدا lambda expressions لإنشائها. تمت إضافة حزمة جديدة java.util.function مع مجموعة من الواجهات الوظيفية لتوفير أنواع الهدف لتعبيرات لامبدا ومراجع الدوال. سنتناول الواجهات الوظيفية وتعبيرات لامبدا في المنشورات المستقبلية.

Source:
https://www.digitalocean.com/community/tutorials/java-8-interface-changes-static-method-default-method