sealed class و sealed interface في Kotlin هما آليتان للتسلسل الهرمي المقيد للأنواع، حيث تكون جميع الفئات الفرعية المحتملة معروفة في وقت الترجمة. على عكس الفئات المجردة العادية، تضمن sealed class معالجة شاملة لجميع المتغيرات في تعبير when. وفقًا لوثائق JetBrains Kotlin Language Guide (2026)، تعد الأنواع sealed الأساس لنمذجة الحالات وشاشات واجهة المستخدم وأنواع النتائج في مشاريع Kotlin.
النقاط الرئيسية
sealed class هي فئة مجردة مع تقييد: يجب الإعلان عن جميع فئاتها الفرعية المباشرة في نفس الملف الذي توجد فيه sealed class. هذا التقييد يجعل التسلسل الهرمي مغلقًا (sealed) — لا يمكن لأي كود خارج الملف إضافة فئة فرعية جديدة.
sealed interface، التي أُضيفت في Kotlin 1.5، توفر نفس الضمان ولكن مع مرونة الواجهة: يمكن تنفيذ sealed interface بواسطة فئات متعددة أو كائنات أو واجهات أخرى في ملف واحد. على عكس sealed class، لا تحتوي sealed interface على تقييد الوراثة الفردية — يمكن للفئة تنفيذ واجهات sealed متعددة في وقت واحد.
وفقًا لـ Kotlin Evolution and Roadmap (2026)، أُضيفت sealed interface بناءً على طلب المجتمع لنمذجة أكثر مرونة. الدافع الرئيسي هو القدرة على الجمع بين التسلسلات الهرمية للأنواع المستقلة دون وراثة متعددة للفئات.
يبدأ إعلان sealed class بالمُعدِّل sealed قبل class. يتم الإعلان عن الفئات الفرعية في نفس الملف.
sealed class NetworkResult {
data class Success(val data: String) : NetworkResult()
data class Error(val message: String) : NetworkResult()
object Loading : NetworkResult()
}
يمكن أن تحتوي كل فئة فرعية من sealed class على خصائصها وطرقها الخاصة. Loading هو كائن فردي (object)، Success و Error هما data classes مع معلمات. يعرف المترجم جميع المتغيرات الثلاثة ويتحقق من اكتمالها عند استخدامها في when.
يمكن أن تكون الفئات sealed متداخلة، مما ينشئ تسلسلات هرمية متعددة المستويات لنماذج بيانات معقدة دون فقدان أمان الأنواع.
sealed class UiState {
object Idle : UiState()
object Loading : UiState()
data class Content(val items: List<Item>) : UiState()
data class Error(val exception: Throwable) : UiState()
}
يتم الإعلان عن sealed interface بشكل مشابه لـ sealed class، ولكنه يسمح بتنفيذ واجهات sealed متعددة في فئة واحدة.
sealed interface Action
sealed interface Loggable
data class Navigate(val route: String) : Action, Loggable
data class ShowToast(val text: String) : Action
object GoBack : Action, Loggable
تقوم فئة Navigate بتنفيذ واجهتين sealed في وقت واحد — Action و Loggable. هذا مستحيل مع sealed class بسبب تقييد الوراثة الفردية. توفر sealed interface مرونة الجمع بين التسلسلات الهرمية المستقلة.
sealed interface مفضلة عندما لا يتطلب التسلسل الهرمي حالة مشتركة أو مُنشئ. وفقًا لإرشادات JetBrains Kotlin Guidelines (2026)، يجب استخدام sealed interface افتراضيًا لجميع التسلسلات الهرمية الجديدة حيث لا تكون هناك حاجة إلى مُنشئ مشترك، مما يجعل الكود أكثر مرونة للتوسعات المستقبلية.
الميزة الرئيسية للأنواع sealed هي المعالجة الشاملة في تعبير when. يتحقق المترجم من تغطية جميع الفئات الفرعية المحتملة.
fun handleResult(result: NetworkResult): String = when (result) {
is NetworkResult.Success -> "Data: ${result.data}"
is NetworkResult.Error -> "Error: ${result.message}"
is NetworkResult.Loading -> "Loading..."
// else غير مطلوب — المترجم يعلم أن جميع المتغيرات مغطاة
}
إذا أضاف المطور فئة فرعية جديدة إلى التسلسل الهرمي sealed لكنه نسي معالجتها في when — سيرمي المترجم خطأ. هذه سلامة على مستوى الأنواع، غير متاحة مع التسلسلات الهرمية المفتوحة التي تستخدم فرع else.
وفقًا لـ Google Android Developers (2026)، الفئات sealed هي الطريقة الموصى بها لنمذجة حالة واجهة المستخدم في Jetpack Compose. يمنع الفحص الشامل لـ when الحالات التي لم يعالج فيها المطور جميع المتغيرات المحتملة لعرض الشاشة.
غالبًا ما يتم الخلط بين enum class و sealed class، لكن لهما أغراض وقدرات مختلفة.
| الخاصية | sealed class | enum class |
|---|---|---|
| الحالات | متعددة (data class)، واحدة (object) | واحدة بالضبط لكل ثابت |
| الخصائص | مختلفة لكل فئة فرعية | نفسها لجميع الثوابت |
| الوراثة | نعم (من sealed class) | لا (نهائي ضمنيًا) |
| المُنشئ | يمكن أن يحتوي على معلمات | مشترك فقط لجميع الثوابت |
| التسلسل الهرمي | مقيد، sealed | مجموعة ثابتة من الثوابت |
يعتمد الاختيار بين sealed class و enum class على المهمة. إذا كانت المتغيرات لا تحمل بيانات إضافية — استخدم enum. إذا كان كل متغير يحتوي على حقول فريدة — استخدم sealed class أو sealed interface.
تُستخدم الأنواع sealed في مشاريع Kotlin لمجموعة من السيناريوهات القياسية حيث تكون النمذجة الآمنة للأنواع مطلوبة.
يمكن أن تحتوي كل شاشة Compose على sealed class UiState تصف جميع الحالات المحتملة: Idle، Loading، Content(data)، Error(exception). يضمن تعبير when معالجة جميع الحالات.
NetworkResult مع المتغيرات Success، Error، Loading هو نمط قياسي في مشاريع Kotlin مع Retrofit و Ktor. توفر sealed class معالجة آمنة لكل نتيجة من نتائج الطلب.
sealed interface لمسارات التنقل تسمح للوحدات بالإعلان عن مساراتها الخاصة مع البقاء ضمن تسلسل هرمي موحد. هذا يلغي الأخطاء المتعلقة بالمسارات غير المعروفة في وقت الترجمة.
وفقًا لـ KotlinConf (2025)، فإن sealed class و sealed interface هما أساس التصميم الآمن للأنواع في تطبيقات Kotlin الحديثة. يتم دمجهما مع data class لنمذجة هياكل المجال المعقدة دون فقدان الأمان في وقت الترجمة.
الأسئلة المتكررة
جميع الفئات الفرعية المباشرة لـ sealed class يجب الإعلان عنها في نفس الملف. بالنسبة لـ sealed interface تنطبق نفس القاعدة — التطبيقات في ملف واحد.
لا، قاعدة الملف الواحد تنطبق أيضًا على sealed interface. يجب أن تكون جميع التطبيقات في الملف الذي تم الإعلان فيه عن sealed interface.
sealed interface ليس لها حالة أو مُنشئ وتسمح بالتطبيق المتعدد. يمكن أن تحتوي sealed class على مُنشئ وحالة مشتركة، لكن الفئة يمكنها أن ترث sealed class واحدًا فقط.
يتحقق المترجم من اكتمال when: إذا لم يتم معالجة جميع الفئات الفرعية، لا يتم ترجمة الكود. هذا يلغي أخطاء وقت التشغيل ويجعل الكود أكثر أمانًا.
نعم، يمكن أن تحتوي sealed class على مُنشئ (خاص افتراضيًا). يمكن لجميع الفئات الفرعية تمرير المعلمات إلى هذا المُنشئ عبر super().
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا