0Pricing
Kotlin Academy · درس

المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل

طبّق المفوّضات على SharedPreferences وتخزين Map وتسجيل التدقيق.

المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.

الخصائص المدعومة بـ Map

تتيح Kotlin تفويض الخصائص إلى Map مباشرةً. وتبحث قراءة الخاصية عن اسمها في الخريطة.

class User(map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}
fun main() {
    val u = User(mapOf("name" to "Alice", "age" to 30))
    println(u.name) // Alice
    println(u.age)  // 30
}

مفوِّض MutableMap

بالنسبة إلى الخصائص القابلة للتغيير، فوِّضها إلى MutableMap بحيث تُحدِّث التغييرات الخريطة الأساسية.

class Settings(private val map: MutableMap<String, Any?> = mutableMapOf()) {
    var theme: String by map
    var fontSize: Int by map
}
fun main() {
    val s = Settings()
    s.theme = "dark"
    s.fontSize = 16
    println(s.theme)    // dark
    println(s.fontSize) // 16
}

إلغاء تسلسل JSON باستخدام مفوِّض Map

حلّل خريطة شبيهة بـ JSON وأتِح حقولها كخصائص محددة النوع باستخدام تفويض الخريطة — وهذا مناسب جدًا للبيانات الديناميكية.

class ApiResponse(data: Map<String, Any?>) {
    val id: Int by data
    val title: String by data
    val published: Boolean by data
}
fun main() {
    val response = ApiResponse(mapOf("id" to 1, "title" to "Kotlin Rocks", "published" to true))
    println(response.title)     // Kotlin Rocks
    println(response.published) // true
}

نمط مفوِّض التسجيل

غلّف أي مفوِّض بالتسجيل لتتبّع كل عملية قراءة وكتابة بشفافية عبر جميع الخصائص المفوَّضة.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Logged<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(t: Any?, p: KProperty<*>): T {
        println("[READ]  ${p.name} = $v"); return v
    }
    override fun setValue(t: Any?, p: KProperty<*>, value: T) {
        println("[WRITE] ${p.name}: $v -> $value"); v = value
    }
}
var config: String by Logged("default")
fun main() { println(config); config = "production" }

دمج Map مع التسجيل

ضع غلافًا للتسجيل حول تفويض الخريطة للحصول على إمكانية تدقيق كاملة للوصول إلى الخصائص الديناميكية.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class TrackedMap(private val map: MutableMap<String,Any?> = mutableMapOf()) {
    inner class Delegate<T> : ReadWriteProperty<Any?,T> {
        @Suppress("UNCHECKED_CAST")
        override fun getValue(t:Any?,p:KProperty<*>): T {
            val v = map[p.name] as T; println("read ${p.name}=$v"); return v
        }
        override fun setValue(t:Any?,p:KProperty<*>,value:T) {
            println("write ${p.name}=$value"); map[p.name]=value
        }
    }
    var host: String by Delegate()
}
fun main() { val m=TrackedMap(); m.host="localhost"; println(m.host) }

مفوِّض على نمط SharedPreferences

مفوِّض يخزّن القيم في خريطة داعمة لمحاكاة SharedPreferences — ويمكن تكييفه مع تفضيلات Android الحقيقية باستبدال الخريطة باستدعاءات التفضيلات الفعلية.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val prefs = mutableMapOf<String, Any?>()
fun <T> pref(default: T): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
    @Suppress("UNCHECKED_CAST")
    override fun getValue(t: Any?, p: KProperty<*>): T = prefs.getOrDefault(p.name, default) as T
    override fun setValue(t: Any?, p: KProperty<*>, value: T) { prefs[p.name] = value }
}
object UserPrefs {
    var username: String by pref("Guest")
    var isDarkMode: Boolean by pref(false)
}
fun main() {
    println(UserPrefs.username)   // Guest
    UserPrefs.username = "Alice"
    println(UserPrefs.username)   // Alice
}

مساعدات التفضيلات محددة النوع

أنشئ دوال مساعدة محددة النوع لكل نوع من أنواع التفضيلات البدائية للحصول على مواضع استدعاء أوضح.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val store = mutableMapOf<String,Any?>()
fun stringPref(default: String) = object : ReadWriteProperty<Any?,String> {
    @Suppress("UNCHECKED_CAST")
    override fun getValue(t:Any?,p:KProperty<*>) = store.getOrDefault(p.name, default) as String
    override fun setValue(t:Any?,p:KProperty<*>,v:String) { store[p.name]=v }
}
fun intPref(default: Int) = object : ReadWriteProperty<Any?,Int> {
    @Suppress("UNCHECKED_CAST")
    override fun getValue(t:Any?,p:KProperty<*>) = store.getOrDefault(p.name, default) as Int
    override fun setValue(t:Any?,p:KProperty<*>,v:Int) { store[p.name]=v }
}
object Prefs {
    var name: String by stringPref("default")
    var count: Int by intPref(0)
}
fun main() { Prefs.name="Bob"; Prefs.count=5; println("${Prefs.name}: ${Prefs.count}") }

مفوِّض سجل التدقيق

سجّل كل تغيير في خاصية مع طابع زمني داخل قائمة تدقيق — وهذا مثالي لسيناريوهات الامتثال أو تصحيح الأخطاء.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val audit = mutableListOf<String>()
class AuditDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(t:Any?,p:KProperty<*>) = v
    override fun setValue(t:Any?,p:KProperty<*>,value:T) {
        audit += "[${System.currentTimeMillis()}] ${p.name}: $v -> $value"
        v = value
    }
}
var price: Double by AuditDelegate(9.99)
fun main() {
    price = 12.99
    price = 11.49
    audit.forEach(::println)
}

التحقق من الصحة مع تخزين Map

اجمع بين تخزين الخريطة والتحقق من الصحة: ارفض القيم غير الصالحة قبل كتابتها في الخريطة.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val data = mutableMapOf<String, Any?>()
fun positiveInt(default: Int): ReadWriteProperty<Any?,Int> = object : ReadWriteProperty<Any?,Int> {
    @Suppress("UNCHECKED_CAST")
    override fun getValue(t:Any?,p:KProperty<*>)=data.getOrDefault(p.name,default) as Int
    override fun setValue(t:Any?,p:KProperty<*>,v:Int){
        require(v>=0){"${p.name} must be >= 0"}
        data[p.name]=v
    }
}
object Inventory { var stock: Int by positiveInt(100) }
fun main(){
    Inventory.stock=50; println(Inventory.stock)
    try { Inventory.stock=-1 } catch(e:Exception){ println(e.message) }
}

نمط تركيب المفوِّضات

ركّب سلوكيات مفوِّضات متعددة باستخدام واجهة برمجة بأسلوب المُنشئ: ابدأ بمفوِّض أساسي، ثم أضف التسجيل أو التحقق من الصحة أو التخزين المؤقت.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun <T> ReadWriteProperty<Any?,T>.withLogging(): ReadWriteProperty<Any?,T> {
    val base = this
    return object : ReadWriteProperty<Any?,T> {
        override fun getValue(t:Any?,p:KProperty<*>): T {
            val v = base.getValue(t,p); println("get ${p.name}=$v"); return v
        }
        override fun setValue(t:Any?,p:KProperty<*>,v:T){
            println("set ${p.name}=$v"); base.setValue(t,p,v)
        }
    }
}

عملي: نمط كائن الإعدادات

استخدم تفويض الخريطة لإنشاء كائن إعدادات من مصادر خارجية مثل متغيرات البيئة أو ملف إعدادات JSON.

class AppConfig(private val raw: Map<String, Any?>) {
    val host: String by raw
    val port: Int by raw
    val debug: Boolean by raw
}
fun main() {
    val env = mapOf("host" to "0.0.0.0", "port" to 8080, "debug" to true)
    val cfg = AppConfig(env)
    println("${cfg.host}:${cfg.port} debug=${cfg.debug}")
}

اختبار سريع

ماذا يحدث عند تفويض خاصية إلى Map؟

مراجعة

تتيح المفوِّضات أنماطًا قوية: تفويض الخريطة للبيانات الديناميكية أو بيانات JSON، والاستمرارية على نمط SharedPreferences، وتسجيل التدقيق للامتثال، والتحقق القابل للتركيب — وكل ذلك دون تغيير مواضع الاستدعاء.

الأسئلة الشائعة

هل درس «المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل» مجاني؟

نعم — نص درس «المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.

ماذا ستتعلم في «المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل»؟

طبّق المفوّضات على SharedPreferences وتخزين Map وتسجيل التدقيق. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟

لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟

نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ‏by lazy: تعمّق في التهيئة المؤجلة
  2. مفوّضا observable وvetoable
  3. كتابة مفوّض ReadWriteProperty مخصص
  4. المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل
← العودة إلى Kotlin Academy