Delegált ingatlanok Kotlinban
1. Bemutatkozás
A Kotlin programozási nyelv natív támogatást nyújt az osztály tulajdonságaihoz.
A tulajdonságokat általában közvetlenül a megfelelő mezők támogatják, de ennek nem mindig kell így lennie - mindaddig, amíg megfelelő módon vannak kitéve a külvilágnak, tulajdonságoknak tekinthetők.
Ezt úgy lehet elérni, hogy ezt kezelőkben és beállítókban kezeljük, vagy a Küldöttek.
2. Melyek a delegált tulajdonságok?
Egyszerűen fogalmazva, a delegált tulajdonságokat nem támogatja egy osztály mező, és a delegálást és beállítást egy másik kódrészre delegálják. Ez lehetővé teszi a delegált funkcionalitás kivonását és megosztását több hasonló tulajdonság között - pl. tulajdonságértékek tárolása a térképen külön mezők helyett.
A delegált tulajdonságokat a tulajdonság és az általa használt megbízott deklarálásával használják. A által kulcsszó azt jelzi, hogy a tulajdonságot a megadott küldött ellenőrzi a saját mezője helyett.
Például:
class DelegateExample (térkép: MutableMap) {var name: String by map}
Ez azt a tényt használja, hogy a MutableMap maga is egy megbízott, amely lehetővé teszi, hogy kulcsait tulajdonságként kezelje.
3. Standard delegált tulajdonságok
A Kotlin standard könyvtár egy sor standard küldöttet tartalmaz, amelyek készen állnak a használatra.
Már láttunk egy példát az a használatára MutableMap hogy megváltoztatható tulajdonságot támogasson. Ugyanígy visszaállíthat egy megváltoztathatatlan tulajdonságot az a használatával Térkép - lehetővé teszi az egyes mezők tulajdonságokként való elérését, de soha nem változtatja meg őket.
A lusta A delegate lehetővé teszi egy tulajdonság értékének kiszámítását csak az első hozzáféréskor, majd a gyorsítótárban. Ez hasznos lehet azoknál a tulajdonságoknál, amelyek kiszámítása költséges lehet, és amelyekre soha nem lesz szüksége - például adatbázisból töltve:
class DatabaseBackedUser (userId: String) {val név: String by lazy {queryForValue ("SELECT name FROM users WHERE userId =: userId", mapOf ("userId" to userId)}}
A megfigyelhető A delegate lehetővé teszi a lambda aktiválását, amikor a tulajdonság értéke megváltozik, például a változásértesítések engedélyezése vagy más kapcsolódó tulajdonságok frissítése:
class ObservedProperty {var name: String by Delegates.observable ("") {prop, old, new -> println ("Régi érték: $ régi, Új érték: $ új")}}
A Kotlin 1.4-től kezdődően lehetőség van közvetlenül egy másik ingatlanra is átruházni. Például, ha egy tulajdonságot átnevezünk egy API osztályba, akkor hagyhatjuk a régit a helyén, és egyszerűen átruházhatjuk az újra:
class RenamedProperty {var newName: String = "" @Deprecated ("NewName use helyett") var name: String by this :: newName}
Itt bármikor elérhetjük a név tulajdon, akkor hatékonyan használjuk a új név tulajdon helyett.
4. A küldöttek létrehozása
Időnként meg akarja írni a küldötteket, ahelyett, hogy a már létezőket használja. Ez egy olyan osztály megírásán alapul, amely kiterjeszti a két felület egyikét - ReadOnlyProperty vagy ReadWriteProperty.
Mindkét interfész meghatározza az úgynevezett módszert getValue - amely a delegált tulajdonság aktuális értékének megadására szolgál, amikor elolvassa. Ehhez két argumentumra van szükség, és visszaadja a tulajdonság értékét:
- thisRef - hivatkozás arra az osztályra, amelybe az ingatlan tartozik
- ingatlan - a delegált ingatlan reflexiós leírása
A ReadWriteProperty interfész ezen felül meghatározza az úgynevezett metódust érték beállítása amely a tulajdonság aktuális értékének frissítésére szolgál, amikor az meg van írva. Ehhez három argumentum szükséges, és nincs visszatérési értéke:
- thisRef - Hivatkozás arra az osztályra, amelybe az ingatlan tartozik
- ingatlan - A delegált ingatlan reflexiós leírása
- érték - Az ingatlan új értéke
A Kotlin 1.4-től kezdődően a ReadWriteProperty interfész valójában kiterjed ReadOnlyProperty. Ez lehetővé teszi számunkra, hogy egyetlen küldött osztályt írjunk meg ReadWriteProperty és csak olvasható mezőkhöz használjuk a kódunkban. Korábban két különböző megbízottat kellett volna írnunk - az egyiket csak olvasható mezőkhöz, a másikat pedig változtatható mezőkhöz.
Példaként írjunk egy megbízottat, amely mindig az adatbázis-kapcsolattal kapcsolatban működik, a helyi mezők helyett:
class DatabaseDelegate (readQuery: String, writeQuery: String, id: Any): ReadWriteDelegate {fun getValue (thisRef: R, tulajdonság: KProperty): T {return queryForValue (readQuery, mapOf ("id" - id))} fun setValue ( thisRef: R, tulajdonság: KProperty, érték: T) {frissítés (writeQuery, mapOf ("id" idre, "érték" értékre)}}}
Ez két legfelső szintű függvénytől függ az adatbázis eléréséhez:
- queryForValue - Ehhez némi SQL szükséges, néhány pedig köt és visszaadja az első értéket
- frissítés - Ehhez némi SQL szükséges, más része pedig UPDATE utasításként kezeli és kezeli
Ezután ezt használhatjuk, mint bármelyik rendes küldöttet, és az osztályunkat automatikusan az adatbázis támogatja:
class DatabaseUser (userId: String) {var name: String by DatabaseDelegate ("SELECT name FROM users WHERE userId =: id", "UPDATE users SET name =: value WHERE userId =: id", userId) var email: String by DatabaseDelegate ("E-mail kiválasztása a felhasználóktól WHERE userId =: id", "UPDATE users SET email =: value WHERE userId =: id", userId)}
5. Delegált alkotás delegálása
A Kotlin 1.4-ben egy másik újdonság, hogy delegált osztályaink létrehozását átruházhatjuk egy másik osztályra. Ez a program végrehajtásával működik PropertyDelegateProvider interfész, amelynek egyetlen módszere van a tényleges megbízottként használandó dolgok példányosítására.
Ezt használhatjuk néhány kód végrehajtására a használni kívánt megbízott létrehozása körül - például naplózhatjuk a történteket. Használhatjuk arra is, hogy dinamikusan kiválasszuk azt a küldöttet, amelyet használni fogunk, az általa használt tulajdonság alapján. Például más delegáltunk lehet, ha a tulajdonság érvénytelen:
osztály DatabaseDelegateProvider(readQuery: String, writeQuery: String, id: Any): PropertyDelegateProvider {felülbírálja az operátor szórakoztató ProviderDelegate (thisRef: T, prop: KProperty): ReadWriteDelegate {if (prop.returnType.isMarkedNullable) {return NullableDatabaseDelegate (readQuery, writeQuery, id)} else {return NonNullDatabaseDelegate} readQu
Ez lehetővé teszi számunkra, hogy egyszerűbb kódot írjunk minden küldöttbe, mert nekik csak célzottabb esetekre kell koncentrálniuk. A fentiekben ezt tudjuk NonNullDatabaseDelegate csak olyan tulajdonságokon fogják használni, amelyek nem rendelkeznek a nulla értéket, ezért nincs szükségünk különösebb logikára ennek kezeléséhez.
6. Összefoglalás
A tulajdon delegálása egy hatékony technika, amely lehetővé teszi olyan kód megírását, amely átveszi a többi tulajdonság ellenőrzését, és elősegíti a logika egyszerű megosztását a különböző osztályok között. Ez lehetővé teszi a robusztus, újrafelhasználható logikát, amely úgy néz ki és úgy néz ki, mint a rendszeres ingatlan-hozzáférés.
Ennek a cikknek egy teljesen működő példája megtalálható a GitHub oldalon.