0Pricing
Kotlin Academy · درس

كتابة مفوّض ReadWriteProperty مخصص

نفّذ مفوّض خصائص مخصصًا من الصفر باستخدام ReadWriteProperty.

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

واجهة ReadWriteProperty

ينفّذ المفوّض المخصص ReadWriteProperty<ThisRef, T> مع عاملي getValue وsetValue.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SimpleDelegate<T>(private var value: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}
var x: Int by SimpleDelegate(0)
fun main() { x = 42; println(x) }

ReadOnlyProperty للنوع val

بالنسبة إلى خصائص val للقراءة فقط، نفّذ ReadOnlyProperty<ThisRef, T> باستخدام getValue فقط.

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class Constant<T>(private val value: T) : ReadOnlyProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
}
val pi: Double by Constant(3.14159)
fun main() { println(pi) }

استخدام thisRef للسياق

يتيح thisRef للمفوّض الوصول إلى الكائن الحاوي، ما يمكّنه من تنفيذ سلوك يعتمد على السياق.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class LoggingDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        println("[${thisRef?.javaClass?.simpleName}] get ${property.name} = $v")
        return v
    }
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        println("[${thisRef?.javaClass?.simpleName}] set ${property.name} = $value")
        v = value
    }
}
class Config { var host: String by LoggingDelegate("localhost") }
fun main() { val c = Config(); c.host = "prod.example.com"; println(c.host) }

مفوّض رقمي مقيّد بحدود

مفوّض يقيّد قيمة رقمية ضمن نطاق، ويفرض الثوابت بشفافية.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Clamped(private val min: Int, private val max: Int, initial: Int) : ReadWriteProperty<Any?, Int> {
    private var v = initial.coerceIn(min, max)
    override fun getValue(t: Any?, p: KProperty<*>) = v
    override fun setValue(t: Any?, p: KProperty<*>, value: Int) {
        v = value.coerceIn(min, max)
    }
}
var brightness: Int by Clamped(0, 255, 128)
fun main() {
    brightness = 300; println(brightness) // 255
    brightness = -5;  println(brightness) // 0
    brightness = 100; println(brightness) // 100
}

مفوّض ذاكرة مؤقتة يقبل null

مفوّض يحسب قيمة مرة واحدة ويخزّنها مؤقتًا، مع إمكانية إبطالها بتعيين null.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class CachedNullable<T>(private val compute: () -> T) : ReadWriteProperty<Any?, T?> {
    private var cache: T? = null
    override fun getValue(t: Any?, p: KProperty<*>): T? = cache ?: compute().also { cache = it }
    override fun setValue(t: Any?, p: KProperty<*>, value: T?) { cache = value }
}
var expensiveResult: Int? by CachedNullable { (1..1000).sum() }
fun main() {
    println(expensiveResult) // computed
    println(expensiveResult) // cached
    expensiveResult = null
    println(expensiveResult) // recomputed
}

مفوّض آمن لمؤشرات الترابط باستخدام @Synchronized

أضف أمان مؤشرات الترابط إلى المفوّض باستخدام @Synchronized أو كائن قفل داخلي.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SynchronizedDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    @Synchronized
    override fun getValue(t: Any?, p: KProperty<*>) = v
    @Synchronized
    override fun setValue(t: Any?, p: KProperty<*>, value: T) { v = value }
}
var counter: Int by SynchronizedDelegate(0)
fun main() { counter = 99; println(counter) }

نمط دالة مصنع المفوّض

اعرض المفوّض عبر دالة امتداد تُعيد كائن المفوّض، باتباع أسلوب المكتبة القياسية.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun <T> logged(initial: T): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
    var v = initial
    override fun getValue(t: Any?, p: KProperty<*>): T { println("get ${p.name}"); return v }
    override fun setValue(t: Any?, p: KProperty<*>, value: T) { println("set ${p.name}=$value"); v = value }
}
var name: String by logged("world")
fun main() { println(name); name = "Kotlin" }

مفوّض مع بيانات KProperty الوصفية

يوفّر الوسيط KProperty اسم الخاصية وتعليقاتها التوضيحية، ما يفيد أطر التسجيل أو ORMs.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class AuditDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
    private val history = mutableListOf<String>()
    override fun getValue(t: Any?, p: KProperty<*>) = v
    override fun setValue(t: Any?, p: KProperty<*>, value: T) {
        history.add("${p.name}: $v -> $value")
        v = value
    }
    fun printHistory() = history.forEach(::println)
}
var status: String by AuditDelegate("idle").also { /* expose audit */ }

عامل provideDelegate

يتيح provideDelegate للمفوّض اعتراض إعداد التفويض، والتحقق من اسم الخاصية أو تعليقاتها التوضيحية عند التهيئة.

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class ValidatedDelegate<T>(private val v: T) {
    operator fun provideDelegate(t: Any?, p: KProperty<*>): ReadOnlyProperty<Any?, T> {
        require(p.name.isNotBlank()) { "Property name must not be blank" }
        return ReadOnlyProperty { _, _ -> v }
    }
}
val greeting: String by ValidatedDelegate("Hello")
fun main() { println(greeting) }

مقارنة الأساليب

المفوّضات المخصصة مقارنةً بـ observable/vetoable: استخدم المضمّنة للأنماط التفاعلية البسيطة، واكتب مفوّضات مخصصة للثوابت المعقدة أو التخزين المؤقت أو السلوك المعتمد على السياق.

// Built-in: simple change notification
import kotlin.properties.Delegates
var simple: Int by Delegates.observable(0) { _,_,v -> println("changed: $v") }
// Custom: clamping + logging
var complex: Int by run {
    object : kotlin.properties.ReadWriteProperty<Any?,Int> {
        var v = 0
        override fun getValue(t:Any?,p:kotlin.reflect.KProperty<*>)=v
        override fun setValue(t:Any?,p:kotlin.reflect.KProperty<*>,value:Int){
            println("clamping $value"); v=value.coerceIn(0,100)
        }
    }
}
fun main() { simple=5; complex=200; println(complex) }

تطبيقي: مفوِّض SharedPreferences

نمط شائع في Android: فوِّض خاصية إلى SharedPreferences بحيث تُحفَظ عمليات القراءة والكتابة تلقائيًا على القرص.

// Pseudocode (no Android runtime here)
class PrefDelegate(private val key: String, private val default: String) {
    // In real Android code:
    // override fun getValue(...) = prefs.getString(key, default) ?: default
    // override fun setValue(...) { prefs.edit().putString(key, value).apply() }
    fun getValue(): String = default // simplified
}
fun main() {
    val delegate = PrefDelegate("user_name", "Guest")
    println(delegate.getValue())
}

اختبار سريع

ما الواجهة التي يجب أن يطبّقها المفوِّض القابل للقراءة والكتابة؟

مراجعة

تطبّق المفوِّضات المخصّصة ReadWriteProperty (أو ReadOnlyProperty)، ويمكنها تغليف التسجيل والتخزين المؤقت والتحقق من الصحة وتقييد القيم أو تخزين المنصة خلف واجهة خصائص شفافة.

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

هل درس «كتابة مفوّض ReadWriteProperty مخصص» مجاني؟

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

ماذا ستتعلم في «كتابة مفوّض ReadWriteProperty مخصص»؟

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

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

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

كم من الوقت يستغرق درس «كتابة مفوّض ReadWriteProperty مخصص»؟

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

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

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

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

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