فئات البيانات والفئات المحصورة
استخدم فئات البيانات للمساواة القائمة على القيمة وcopy()، والفئات المحصورة لبُنى الأنواع الشاملة ونمذجة الحالات بوضوح.
فئات البيانات والفئات المحصورة درس مجاني في Android Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Android Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Android Academy 4 دروس في المجموع.
ما هي فئات البيانات؟
فئة البيانات في Kotlin هي فئة هدفها الأساسي حفظ البيانات. وينشئ المترجم تلقائيًا أساليب مفيدة لكم:
equals()— مقارنة نسختين حسب القيمةhashCode()— تجزئة متسقة تستند إلى الخصائصtoString()— تمثيل نصي سهل القراءةcopy()— إنشاء نسخة معدّلة- دعم التفكيك
تعريف فئة بيانات
أضف الكلمة المفتاحية data قبل class. يجب أن تكون جميع الخصائص في المُنشئ الأساسي:
data class User(val id: Int, val name: String, val email: String)
fun main() {
val u1 = User(1, "Alice", "alice@example.com")
val u2 = User(1, "Alice", "alice@example.com")
println(u1) // User(id=1, name=Alice, email=alice@example.com)
println(u1 == u2) // true (value equality)
println(u1 === u2) // false (different objects)
}copy() — تعديل حقل واحد
تنشئ copy() نسخة جديدة مع تغيير بعض الخصائص. ولا يتم تعديل الأصل (عدم القابلية للتغيير):
data class Product(val name: String, val price: Double, val inStock: Boolean)
fun main() {
val original = Product("Laptop", 999.0, true)
// Only change the price; keep everything else
val onSale = original.copy(price = 799.0)
println(original) // Product(name=Laptop, price=999.0, inStock=true)
println(onSale) // Product(name=Laptop, price=799.0, inStock=true)
}إعلانات التفكيك
تدعم فئات البيانات التفكيك — فكّك الخصائص إلى متغيرات باستخدام دوال componentN() التي ينشئها المصرّف:
data class Point(val x: Int, val y: Int)
fun main() {
val point = Point(10, 20)
// Destructure into separate variables
val (x, y) = point
println("x=$x, y=$y") // x=10, y=20
// Also works in for loops with maps
val scores = mapOf("Alice" to 95, "Bob" to 88)
for ((name, score) in scores) {
println("$name: $score")
}
}ما هي الفئات المحكَمة؟
الفئة المحكَمة هي تسلسل هرمي مقيّد للفئات — يجب تعريف جميع الفئات الفرعية في الملف نفسه. وهذا يجعل مجموعة الأنواع المحتملة معروفة وقت الترجمة.
استخدم الفئات المحكَمة لتمثيل مجموعة محدودة من الحالات، مثل نتائج الشبكة أو حالات واجهة المستخدم أو أحداث التنقل.
صيغة الفئة المحكَمة
صرّح عن الفئات الفرعية مباشرةً داخل الملف نفسه أو فيه:
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val message: String, val code: Int = 0) : NetworkResult<Nothing>()
object Loading : NetworkResult<Nothing>()
}
fun handle(result: NetworkResult<String>) {
when (result) {
is NetworkResult.Success -> println("Data: ${result.data}")
is NetworkResult.Error -> println("Error ${result.code}: ${result.message}")
NetworkResult.Loading -> println("Loading...")
}
}الفئة المحكَمة + when (شاملة)
تكمن قوة الفئات المحكَمة في أن when تكون شاملة. يُجبرك المصرّف على معالجة كل نوع فرعي — دون حالات منسية:
sealed class UiState {
object Loading : UiState()
data class Success(val message: String) : UiState()
data class Error(val error: String) : UiState()
}
fun render(state: UiState): String = when (state) {
is UiState.Loading -> "Showing spinner"
is UiState.Success -> "Show: ${state.message}"
is UiState.Error -> "Error: ${state.error}"
// Compiler error if you remove any branch!
}
fun main() {
println(render(UiState.Loading))
println(render(UiState.Success("Loaded!")))
}الفئة المحكَمة مقابل التعداد
يمثل كلاهما مجموعة ثابتة من القيم، لكن:
- Enum — كل ثابت هو نسخة واحدة، ولا توجد بيانات إضافية لكل متغير
- الفئة المحكَمة — يمكن لكل متغير حمل بيانات مختلفة، وأن يكون فئة أو كائنًا
استخدم enum عندما لا تحتاج المتغيرات إلى بيانات. واستخدم الفئة المحكَمة عندما تحتاج المتغيرات إلى خصائص مختلفة.
إعلانات الكائنات (Singletons)
ينشئ object كائنًا مفردًا — نسخة واحدة، تُنشأ عند الطلب، وآمنة مع تعدد مؤشرات التنفيذ:
object AppConfig {
const val BASE_URL = "https://api.example.com"
const val TIMEOUT = 30L
fun buildUrl(path: String) = "$BASE_URL/$path"
}
fun main() {
println(AppConfig.BASE_URL) // https://api.example.com
println(AppConfig.buildUrl("users")) // https://api.example.com/users
}الكائنات المرافقة
يعيش الكائن المرافق داخل فئة ويوفّر أعضاء على مستوى الفئة (مثل static في Java). ويُستخدم عادةً لأساليب إنشاء الكائنات:
class Token private constructor(val value: String) {
companion object {
fun create(raw: String): Token {
val cleaned = raw.trim()
require(cleaned.isNotEmpty()) { "Token must not be blank" }
return Token(cleaned)
}
}
}
fun main() {
val token = Token.create(" abc123 ")
println(token.value) // abc123
}فئات البيانات في تطبيق حقيقي
اجمع بين فئات البيانات والفئات المحكَمة لنمذجة الحالات بطريقة منظمة:
data class Post(val id: Int, val title: String, val body: String)
sealed class PostState {
object Loading : PostState()
data class Loaded(val posts: List<Post>) : PostState()
data class Failed(val reason: String) : PostState()
}
fun showState(state: PostState) = when (state) {
PostState.Loading -> println("Fetching posts...")
is PostState.Loaded -> println("${state.posts.size} posts loaded")
is PostState.Failed -> println("Failed: ${state.reason}")
}
fun main() {
showState(PostState.Loaded(listOf(
Post(1, "Hello", "World"),
Post(2, "Kotlin", "Rocks")
)))
}تحقق سريع
أي عبارة تشرح على أفضل نحو ما يميز الفئات المحكَمة عن الفئات المجردة العادية؟
مراجعة: فئات البيانات والفئات المحكَمة
أصبحت لديك الآن أداتان قويتان في Kotlin:
- data class — مساواة قائمة على القيمة، و
copy()، والتفكيك، وtoString()المُنشأة تلقائيًا - sealed class — تسلسل هرمي محدود للأنواع، و
whenشاملة، ويمكن لكل متغير حمل بياناته الخاصة - object — كائن مفرد، وكائنات مرافقة لأساليب إنشاء الكائنات
تستبدل هذه الأنماط معًا الشيفرة المتكررة في Java، وتتيح نمذجة الحالات بطريقة منظمة وآمنة.
الأسئلة الشائعة
هل درس «فئات البيانات والفئات المحصورة» مجاني؟
نعم — نص درس «فئات البيانات والفئات المحصورة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Android Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Android Academy 4 دروس في المجموع.
ماذا ستتعلم في «فئات البيانات والفئات المحصورة»؟
استخدم فئات البيانات للمساواة القائمة على القيمة وcopy()، والفئات المحصورة لبُنى الأنواع الشاملة ونمذجة الحالات بوضوح. تتمرن على Android Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Android Academy؟
لا تُشترط خبرة سابقة. Android Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «فئات البيانات والفئات المحصورة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Android Academy هذا؟
نعم. كل درس في Android Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أمان القيم الفارغة
- الفئات والكائنات
- فئات البيانات والفئات المحصورة
- دوال الامتداد والدوال عالية الرتبة