Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الـ Sealed Classes (Java 17+)

جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 52 من 87.

في Java التقليدية، عندما تنشئ class، يمكن لأي class أخرى أن ترث منها (ما لم تضع عليها العلامة final). ولكن ماذا لو أردت السماح بالوراثة، ولكن ليس من أي شخص؟ قدّمت Java 17 الفئات المختومة لتمنحك تحكمًا دقيقًا في الفئات التي يمكنها أن ترث من فئتك.

يُصرّح الصنف المختوم بشكل صريح بالفئات الفرعية المسموح بها باستخدام الكلمتين المفتاحيتين sealed وpermits:

sealed abstract class Shape permits Circle, Rectangle, Triangle {
    abstract double area();
}

final class Circle extends Shape {
    double radius;
    double area() { return Math.PI * radius * radius; }
}

final class Rectangle extends Shape {
    double width, height;
    double area() { return width * height; }
}

final class Triangle extends Shape {
    double base, height;
    double area() { return 0.5 * base * height; }
}

يمكن فقط لـ Circle وRectangle وTriangle أن ترث من Shape. وأي class أخرى تحاول أن ترث منها ستؤدي إلى حدوث خطأ في الترجمة.

يجب أن تستخدم كل فئة فرعية مسموح بها واحدًا من ثلاثة مُعدِّلات: final (لا مزيد من التوسعة)، أو sealed (تستمر سلسلة التقييد)، أو non-sealed (يفتح المجال للتوسعة غير المقيّدة):

sealed class Vehicle permits Car, Truck { }

final class Car extends Vehicle { }           // لا يمكن تمديده
non-sealed class Truck extends Vehicle { }    // يمكن لأي شخص تمديد Truck

تكون sealed classes قوية بشكل خاص مع pattern matching في تعبيرات switch، إذ يعرف المصرّف جميع الأنواع الفرعية الممكنة ويمكنه التحقق من الاكتمال. وهي مثالية عند نمذجة مجموعة ثابتة من الأنواع في مجال معيّن، مثل طرق الدفع أو أنواع الاستجابات أو الأشكال الهندسية.

challenge icon

التحدي

سهل

لنبنِ نظام إشعارات يوضّح استخدام الفئات المختومة من خلال تقييد أنواع الإشعارات التي يمكن أن توجد في تطبيقك. ستنشئ تسلسلاً هرميًا يُسمح فيه بأنواع محددة فقط من الإشعارات، ويتولى كل نوع عملية التسليم بطريقة مختلفة.

ستنظّم الشيفرة عبر أربعة ملفات:

  • Notification.java: أنشئ فئة abstract مختومة تعمل كفئة أساسية لجميع الإشعارات. يجب أن تسمح بثلاث فئات فرعية بالضبط: EmailNotification وSMSNotification وPushNotification. يجب أن تحتوي الفئة المختومة على الحقل المحمي message (من النوع String)، وبانٍ لتهيئته، وgetter للرسالة، وطريقة مجردة deliver() تُرجع قيمة من النوع String تصف كيفية إرسال الإشعار.
  • EmailNotification.java: أنشئ فئة final تمتد من Notification. تحتوي EmailNotification على حقل خاص إضافي هو recipient (من النوع String) لعنوان البريد الإلكتروني. يجب أن يستقبل بانِيها كلاً من الرسالة والمستلم، مع استدعاء بانِي الفئة الأصل باستخدام super(). يجب أن تُرجع الطريقة deliver(): Sending email to [recipient]: [message]
  • SMSNotification.java: أنشئ فئة non-sealed تمتد من Notification. يتيح ذلك للفئات الأخرى أن تمتد منها إذا لزم الأمر في المستقبل. تحتوي SMSNotification على حقل خاص إضافي هو phoneNumber (من النوع String). يستقبل بانِيها الرسالة ورقم الهاتف. يجب أن تُرجع الطريقة deliver(): Sending SMS to [phoneNumber]: [message]
  • PushNotification.java: أنشئ فئة final تمتد من Notification. تحتوي PushNotification على حقل خاص إضافي هو deviceId (من النوع String). يستقبل بانِيها الرسالة ومعرّف الجهاز. يجب أن تُرجع الطريقة deliver(): Sending push to device [deviceId]: [message]
  • Main.java: اجمع نظام الإشعارات لديك! ستتلقى أربعة مدخلات: رسالة (String)، وعنوان بريد إلكتروني (String)، ورقم هاتف (String)، ومعرّف جهاز (String).

    أنشئ مثيلاً واحدًا من كل نوع من أنواع الإشعارات باستخدام الرسالة نفسها، ولكن مع معلومات الاتصال الخاصة بكل منها. خزّن الأنواع الثلاثة جميعًا في مصفوفة من النوع Notification[] لتوضيح تعدد الأشكال باستخدام الفئات المختومة. ثم تكرّر عبر المصفوفة وتطبع نتيجة استدعاء deliver() على كل إشعار.

ستتلقى أربعة مدخلات بالترتيب التالي: الرسالة، وعنوان البريد الإلكتروني، ورقم الهاتف، ومعرّف الجهاز.

لاحظ كيف تقيّد الفئة المختومة التسلسل الهرمي: يمكن للفئات الثلاث المسموح بها فقط أن تمتد من Notification. يجب أن تعلن كل فئة فرعية عن نفسها باستخدام final أو sealed أو non-sealed. يمنحك ذلك تحكمًا كاملاً في التسلسل الهرمي للأنواع، مع الاستمرار في تمكين تعدد الأشكال!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // قراءة المدخلات الأربعة
        String message = scanner.nextLine();
        String email = scanner.nextLine();
        String phoneNumber = scanner.nextLine();
        String deviceId = scanner.nextLine();
        
        // TODO: إنشاء إشعار واحد من كل نوع باستخدام نفس الـ message
        // - EmailNotification باستخدام message و email
        // - SMSNotification باستخدام message و phoneNumber
        // - PushNotification باستخدام message و deviceId
        
        // TODO: تخزين جميع الإشعارات الثلاثة في مصفوفة Notification[]
        // هذا يوضح مفهوم تعدد الأشكال (polymorphism) مع sealed classes
        
        // TODO: التكرار عبر المصفوفة وطباعة نتيجة deliver()
        // لكل إشعار
        
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Java عبر الإنترنت