Delegaty dla Preferences, właściwości opartych na Map i logowania
Zastosuj delegaty do SharedPreferences, przechowywania w Map i rejestrowania audytowego.
Delegaty dla Preferences, właściwości opartych na Map i logowania to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Właściwości oparte na Map
Kotlin umożliwia bezpośrednie delegowanie właściwości do obiektu Map. Odczyt właściwości wyszukuje jej nazwę w mapie.
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
}Delegat MutableMap
W przypadku właściwości mutowalnych należy delegować do MutableMap, a modyfikacje będą aktualizować bazową mapę.
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
}Deserializacja JSON z delegatem Map
Przeanalizuj mapę podobną do JSON-a i udostępnij jej pola jako właściwości o określonych typach za pomocą delegowania do mapy — to świetne rozwiązanie w przypadku dynamicznych danych.
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
}Wzorzec delegata z logowaniem
Owiń dowolny delegat logowaniem, aby w przejrzysty sposób śledzić każdy odczyt i zapis we wszystkich delegowanych właściwościach.
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" }Łączenie Map i logowania
Dodaj warstwę opakowującą z logowaniem wokół delegowania do mapy, aby zapewnić pełną rozliczalność dostępu do dynamicznych właściwości.
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) }Delegat w stylu SharedPreferences
Delegat przechowujący wartości w bazowej mapie, która symuluje SharedPreferences — aby dostosować go do rzeczywistych preferencji Androida, wystarczy zastąpić mapę wywołaniami prawdziwych preferencji.
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
}Pomocnicze funkcje typowanych preferencji
Utwórz typowane funkcje pomocnicze dla każdego pierwotnego typu preferencji, aby wywołania były czytelniejsze.
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}") }Delegat dziennika audytowego
Zapisuj każdą zmianę właściwości wraz ze znacznikiem czasu na liście audytowej — to idealne rozwiązanie w scenariuszach związanych ze zgodnością lub debugowaniem.
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)
}Walidacja i magazynowanie w Map
Połącz magazynowanie w mapie z walidacją: odrzucaj nieprawidłowe wartości przed zapisaniem ich w mapie.
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) }
}Wzorzec składania delegatów
Składaj wiele zachowań delegatów za pomocą interfejsu w stylu buildera: zacznij od bazowego delegata, a następnie dodaj logowanie, walidację lub buforowanie.
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)
}
}
}Praktyka: wzorzec obiektu konfiguracji
Użyj delegowania do mapy, aby utworzyć obiekt konfiguracji z zewnętrznych źródeł, takich jak zmienne środowiskowe lub plik konfiguracji 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}")
}Szybkie sprawdzenie
Co się dzieje, gdy delegujesz właściwość do obiektu Map?
Podsumowanie
Delegaty umożliwiają tworzenie zaawansowanych wzorców: delegowanie do mapy na potrzeby dynamicznych danych i danych JSON, utrwalanie w stylu SharedPreferences, rejestrowanie audytowe na potrzeby zgodności oraz składanie walidacji — wszystko to bez zmiany miejsc wywołań.
Ucz się Kotlin dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 51
- Lekcje
- 203
Często zadawane pytania
Czy lekcja „Delegaty dla Preferences, właściwości opartych na Map i logowania” jest bezpłatna?
Tak — pełny tekst „Delegaty dla Preferences, właściwości opartych na Map i logowania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Delegaty dla Preferences, właściwości opartych na Map i logowania”?
Zastosuj delegaty do SharedPreferences, przechowywania w Map i rejestrowania audytowego. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Delegaty dla Preferences, właściwości opartych na Map i logowania”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- by lazy: szczegółowe omówienie odroczonej inicjalizacji
- Delegaty observable i vetoable
- Pisanie własnego delegata ReadWriteProperty
- Delegaty dla Preferences, właściwości opartych na Map i logowania