مفوّضا observable وvetoable
استجب لتغييرات الخصائص باستخدام observable وارفضها بشروط باستخدام vetoable.
مفوّضا observable وvetoable درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
مراجعة مفوّضي الخصائص
تتيح مفوّضات خصائص Kotlin لكائن منفصل التعامل مع getValue وsetValue. ويُعد Delegates.observable وDelegates.vetoable مفوّضين مضمّنين في المكتبة القياسية.
import kotlin.properties.Delegates
var name: String by Delegates.observable("initial") { prop, old, new ->
println("${prop.name}: $old -> $new")
}
fun main() { name = "Alice"; name = "Bob" }صياغة observable
تستقبل observable قيمة ابتدائية واستدعاءً عكسيًا يُستدعى بعد كل تغيير، مع تمرير الخاصية والقيمة القديمة والقيمة الجديدة.
import kotlin.properties.Delegates
var score: Int by Delegates.observable(0) { _, old, new ->
println("Score changed from $old to $new")
}
fun main() {
score = 10
score = 25
score = 0
}تشغيل تحديثات واجهة المستخدم
تُعد المفوّضات القابلة للمراقبة مناسبة جدًا لتشغيل تحديث واجهة المستخدم عند تغيّر خاصية داعمة، من دون إعداد كامل لـ LiveData.
import kotlin.properties.Delegates
class ViewModel {
var title: String by Delegates.observable("Loading") { _, _, new ->
println("Render: $new") // pretend this updates UI
}
}
fun main() {
val vm = ViewModel()
vm.title = "Home"
vm.title = "Settings"
}صياغة vetoable
تستدعي vetoable استدعاءً عكسيًا قبل التعيين. فإذا أعاد الاستدعاء false، تُرفض القيمة الجديدة وتبقى القيمة القديمة.
import kotlin.properties.Delegates
var age: Int by Delegates.vetoable(0) { _, old, new ->
new >= 0 // reject negative ages
}
fun main() {
age = 25; println(age) // 25
age = -1; println(age) // 25 (rejected)
age = 30; println(age) // 30
}دمج التحقق مع vetoable
استخدم vetoable لفرض ثوابت المجال على مستوى الخاصية، من دون الحاجة إلى منطق تحقق خارجي.
import kotlin.properties.Delegates
var email: String by Delegates.vetoable("") { _, _, new ->
new.contains("@")
}
fun main() {
email = "user@example.com"; println(email) // set
email = "invalid"; println(email) // still previous
}تسجيل التغييرات باستخدام observable
استخدم observable لتسجيل التدقيق: سجّل كل انتقال في الحالة تلقائيًا من دون تعديل منطق العمل.
import kotlin.properties.Delegates
val log = mutableListOf<String>()
var status: String by Delegates.observable("IDLE") { _, old, new ->
log.add("$old -> $new")
}
fun main() {
status = "RUNNING"
status = "DONE"
println(log)
}استخدام observable داخل فئة
يعمل كلا المفوّضين داخل أجسام الفئات مثل أي خاصية أخرى.
import kotlin.properties.Delegates
class Counter {
var count: Int by Delegates.observable(0) { _, old, new ->
if (new > old) println("Incremented to $new")
else println("Decremented to $new")
}
}
fun main() {
val c = Counter()
c.count = 5
c.count = 3
}استخدام vetoable لفرض قيد نطاق
قيّد خاصية رقمية بنطاق صالح باستخدام vetoable.
import kotlin.properties.Delegates
var volume: Int by Delegates.vetoable(50) { _, _, new ->
new in 0..100
}
fun main() {
volume = 80; println(volume) // 80
volume = 150; println(volume) // 80 (rejected)
volume = 0; println(volume) // 0
}سلاسل المفوّضات
يمكنك دمج منطق observable يدويًا عبر كتابة مفوّض مخصص يستدعي observable داخليًا، مع إضافة منطق إضافي في كل خطوة.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class LoggedDelegate<T>(initial: T) : ReadWriteProperty<Any?, T> {
private var value: T = initial
override fun getValue(t: Any?, p: KProperty<*>) = value
override fun setValue(t: Any?, p: KProperty<*>, v: T) {
println("Setting ${p.name} = $v"); value = v
}
}
var x: Int by LoggedDelegate(0)
fun main() { x = 10; x = 20 }ملاحظة حول أمان مؤشرات الترابط
لا يتمتع observable ولا vetoable بأمان مؤشرات الترابط افتراضيًا. وللوصول المتزامن، احمِ عمليات التعديل باستخدام Mutex أو نفّذ المزامنة خارجيًا.
import kotlin.properties.Delegates
// Not thread-safe as-is:
var sharedState: String by Delegates.observable("start") { _, old, new ->
println("$old -> $new")
}
// In coroutines, wrap access with Mutex if neededنمط عملي: التحقق من صحة النموذج
استخدم vetoable لكل حقل للتحقق التصريحي من صحة النموذج: يتحقق كل حقل من صحته ذاتيًا عند التعيين.
import kotlin.properties.Delegates
data class Form(
var username: String = "",
var password: String = ""
) {
var validUsername: String by Delegates.vetoable("") { _,_,v -> v.length >= 3 }
var validPassword: String by Delegates.vetoable("") { _,_,v -> v.length >= 8 }
}
fun main() {
val f = Form()
f.validUsername = "ab"; println(f.validUsername) // ""
f.validUsername = "alice"; println(f.validUsername) // "alice"
f.validPassword = "short"; println(f.validPassword) // ""
f.validPassword = "secure123";println(f.validPassword) // "secure123"
}اختبار سريع
متى تستدعي vetoable الاستدعاء العكسي الخاص بها؟
مراجعة
يُشعِر observable بالتغيير بعد كل عملية تغيير، بينما ينفّذ vetoable الاستدعاء قبل التعيين ويمكنه رفض القيمة الجديدة. وكلاهما مناسب للتسجيل والتحقق وأنماط الخصائص التفاعلية من دون مكتبات خارجية.
الأسئلة الشائعة
هل درس «مفوّضا observable وvetoable» مجاني؟
نعم — نص درس «مفوّضا observable وvetoable» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «مفوّضا observable وvetoable»؟
استجب لتغييرات الخصائص باستخدام observable وارفضها بشروط باستخدام vetoable. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «مفوّضا observable وvetoable»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- by lazy: تعمّق في التهيئة المؤجلة
- مفوّضا observable وvetoable
- كتابة مفوّض ReadWriteProperty مخصص
- المفوّضات للتفضيلات والخصائص المدعومة بـ Map والتسجيل