נכסים מאושרים בקוטלין

1. הקדמה

לשפת התכנות Kotlin יש תמיכה מקורית במאפייני הכיתה.

נכסים מגובים בדרך כלל ישירות על ידי שדות תואמים, אך לא תמיד זה צריך להיות כך - כל עוד הם נחשפים כראוי לעולם החיצון, הם עדיין יכולים להיחשב כמאפיינים.

ניתן להשיג זאת על ידי טיפול בזה בגטרים וקובעים, או על ידי מינוף הכוח של צירים.

2. מהם הנכסים המואצלים?

במילים פשוטות, מאפיינים המואצלים אינם מגובים בשדה מחלקה ונציגים מקבלים והגדרת פיסת קוד אחרת. זה מאפשר הפשטה של ​​פונקציונליות מוסמכת ושיתוף בין מאפיינים דומים מרובים - למשל. שמירת ערכי מאפיינים במפה במקום שדות נפרדים.

נעשה שימוש במאפיינים מוסמכים על ידי הכרזת הנכס והנציח בו הוא משתמש. ה על ידי מילת מפתח מציינת כי הנכס נשלט על ידי הנציג שסופק במקום השדה שלו.

לדוגמה:

class DelegateExample (map: MutableMap) {var name: מחרוזת לפי מפה}

זה משתמש בעובדה שא מפה משתנה הוא בעצמו נציג, המאפשר לך להתייחס למפתחות שלו כאל מאפיינים.

3. נכסים מוסמכים רגילים

הספרייה הסטנדרטית של קוטלין מגיעה עם קבוצה של נציגים סטנדרטיים שמוכנים לשימוש.

ראינו כבר דוגמה לשימוש ב- מפה משתנה לגבות נכס משתנה. באותו אופן, אתה יכול לגבות נכס בלתי משתנה באמצעות מַפָּה - מתן אפשרות לגשת לשדות בודדים כמאפיינים, אך לעולם לא לשנות אותם.

ה עָצֵל נציג מאפשר לחשב את ערך הנכס רק בגישה הראשונה ואז במטמון. זה יכול להיות שימושי למאפיינים שעשויים להיות יקרים לחישוב ושייתכן שלא תזדקק להם לעולם - למשל לטעון ממסד נתונים:

class DatabaseBackedUser (userId: String) {val name: String by lazy {queryForValue ("SELECT name FROM users WHERE userId =: userId", mapOf ("userId" to userId)}}

ה נצפה הנציג מאפשר להפעיל למבדה בכל פעם שערך הנכס משתנה, למשל, מאפשר הודעות על שינוי או עדכון של מאפיינים קשורים אחרים:

class ObservedProperty {var name: String by Delegates.observable ("") {prop, old, new -> println ("value old: $ old, new value: $ new")}}

נכון לקוטלין 1.4, ניתן גם להאציל ישירות לנכס אחר. לדוגמא, אם אנו משנים שם למאפיין בכיתת API, אנו עשויים להשאיר את הישן במקום ופשוט להאציל לקטגוריה החדשה:

class RenamedProperty {var newName: String = "" @Deprecated ("השתמש שם חדש במקום") שם var: מחרוזת לפי זה :: newName}

כאן, בכל פעם שניגש ל שֵׁם נכס, אנו משתמשים ביעילות שם חדש נכס במקום.

4. יצירת הנציגים שלך

יהיו פעמים שתרצה לכתוב את הנציגים שלך במקום להשתמש בכאלה שכבר קיימים. זה מסתמך על כתיבת כיתה המרחיבה אחד משני ממשקים - ReadOnlyProperty אוֹ ReadWriteProperty.

שני הממשקים הללו מגדירים שיטה שנקראת getValue - המשמש לספק את הערך הנוכחי של המאפיין המוקצה בעת קריאתו. זה לוקח שני ארגומנטים ומחזיר את ערך הנכס:

  • thisRef - התייחסות למחלקה בה נמצא הנכס
  • תכונה - תיאור השתקפות של הנכס המועבר

ה ReadWriteProperty ממשק מגדיר בנוסף שיטה שנקראת הגדר ערך המשמש לעדכון הערך הנוכחי של הנכס בעת כתיבתו. זה לוקח שלושה ארגומנטים ואין לו ערך החזרה:

  • thisRef - התייחסות למחלקה בה נמצא הנכס
  • תכונה - תיאור השתקפות של הנכס המועבר
  • ערך - השווי החדש של הנכס

נכון לקוטלין 1.4, ReadWriteProperty ממשק ממש מתארך ReadOnlyProperty. זה מאפשר לנו לכתוב כיתת נציגה אחת מיישמת ReadWriteProperty והשתמש בו לשדות לקריאה בלבד בתוך הקוד שלנו. בעבר היינו צריכים לכתוב שני נציגים שונים - אחד לשדות לקריאה בלבד ואחד לשדות ניתנים לשינוי.

כדוגמה, בוא נכתוב נציג שעובד תמיד לגבי חיבור מסד נתונים במקום שדות מקומיים:

class DatabaseDelegate (readQuery: String, writeQuery: String, id: Any): ReadWriteDelegate {fun getValue (thisRef: R, property: KProperty): T {return queryForValue (readQuery, mapOf ("id" to id))} fun setValue (fun thisRef: R, property: KProperty, value: T) {update (writeQuery, mapOf ("id" to id, "value" to value))}}

זה תלוי בשתי פונקציות ברמה העליונה לגישה למסד הנתונים:

  • queryForValue - זה לוקח קצת SQL וחלק נקשר ומחזיר את הערך הראשון
  • עדכון - זה לוקח קצת SQL וחלק נקשר ומתייחס אליו כאל משפט UPDATE

לאחר מכן נוכל להשתמש בזה כמו כל נציג רגיל ולגבות את הכיתה שלנו באופן אוטומטי על ידי מסד הנתונים:

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: מחרוזת לפי DatabaseDelegate ("בחר דוא"ל ממשתמשים WHERE userId =: id", "UPDATE משתמשים הגדר דוא"ל =: value WHERE userId =: id", userId)}

5. האצלת יצירת נציגים

תכונה חדשה נוספת שיש לנו ב- Kotlin 1.4 היא היכולת להאציל את יצירת הכיתות הנציגות שלנו לכיתה אחרת. זה עובד על ידי יישום ה- PropertyDelegateProvider ממשק, שיש לו שיטה אחת לייצר משהו להשתמש בו כנציח בפועל.

אנו יכולים להשתמש בזה בכדי לבצע קוד כלשהו סביב יצירת הנציג שישמש - למשל, כדי לתעד את המתרחש. אנו יכולים להשתמש בו גם כדי לבחור באופן דינמי את הנציג שאנו נשתמש בו על סמך המאפיין אליו הוא משמש. לדוגמא, ייתכן שיהיה לנו נציג אחר אם המאפיין אינו פעיל:

class DatabaseDelegateProvider(readQuery: String, writeQuery: String, id: Any): PropertyDelegateProvider {לעקוף את fun funDelegate (thisRef: T, prop: KProperty): ReadWriteDelegate {if (prop.returnType.isMarkedNullable) {return NullableDatabaseDelegate (readQuery, writeQuery, id)} אחר {return NonNullDatabaseDelegate (readQuery, writeQuery)

זה מאפשר לנו לכתוב קוד פשוט יותר בכל נציג מכיוון שהם צריכים רק להתמקד בתיקים ממוקדים יותר. באמור לעיל, אנו יודעים זאת NonNullDatabaseDelegate ישמש רק אי פעם בתכונות שלא יכולות להכיל ריק ערך, כך שאנחנו לא צריכים שום היגיון נוסף בכדי לטפל בזה.

6. סיכום

האצלת נכסים היא טכניקה עוצמתית המאפשרת לך לכתוב קוד שמשתלט על שליטה במאפיינים אחרים, ועוזר לחלוק לוגיקה זו בין מחלקות שונות. זה מאפשר היגיון חזק, רב פעמי, שנראה ומרגיש כמו גישה קבועה לרכוש.

דוגמה עובדת לחלוטין למאמר זה ניתן למצוא באתר GitHub.


$config[zx-auto] not found$config[zx-overlay] not found