הזרקת תלות בקוטלין עם קודיין

1. סקירה כללית

במאמר זה נציג את Kodein - מסגרת טהורה של הזרקת תלות Kotlin (DI) - ונשווה אותה עם מסגרות DI פופולריות אחרות.

2. תלות

ראשית, בואו נוסיף את התלות בקודיין pom.xml:

 com.github.salomonbrys.kodein קודין 4.1.0 

לידיעתך, הגרסה האחרונה הזמינה זמינה ב- Maven Central או ב- jCenter.

3. תצורה

נשתמש במודל שלהלן להמחשת תצורה מבוססת קודיין:

בקר מחלקה (שירות שירות פרטי: שירות) מחלקת שירות (שירות אישי פרטי dao: Dao, תג val פרטי: String) ממשק Dao class JdbcDao: Dao class MongoDao: Dao

4. סוגי כריכה

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

4.1. קְלָף בּוֹדֵד

עם קְלָף בּוֹדֵד כריכה, שעועית מטרה מופנית בעצלתיים עם הגישה הראשונה ושימוש חוזר בכל הבקשות הנוספות:

var נוצר = שקר; val kodein = Kodein {bind () with singleton {MongoDao ()}} assertThat (created) .isFalse () val dao1: Dao = kodein.instance () assertThat (created) .isFalse () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

הערה: אנו יכולים להשתמש Kodein.instance () לאחזור שעועית מנוהלת יעד בהתבסס על סוג משתנה סטטי.

4.2. סינגלטון להוט

זה דומה ל- קְלָף בּוֹדֵד כריכה. ההבדל היחיד הוא בכך בלוק האתחול נקרא בשקיקה:

var נוצר = שקר; val kodein = Kodein {bind () with singleton {MongoDao ()}} assertThat (created) .isTrue () val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isSameAs (dao2)

4.3. בית חרושת

עם בית חרושת מחייב, גוש האתחול מקבל ויכוח, ו- אובייקט חדש מוחזר ממנו בכל פעם:

val kodein = Kodein {bind () with singleton {MongoDao ()} bind () with factory {tag: String -> Service (instance (), tag)}} val service1: Service = kodein.with ("myTag"). מופע () val service2: Service = kodein.with ("myTag"). מופע () assertThat (service1) .isNotSameAs (service2)

הערה: אנו יכולים להשתמש Kodein.instance () להגדרת תלות מעבר.

4.4. מולטי טון

מולטי טון הכריכה דומה מאוד ל- בית חרושת כריכה. ההבדל היחיד הוא בכך אותו אובייקט מוחזר עבור אותו טיעון בשיחות הבאות:

val kodein = Kodein {bind () with singleton {MongoDao ()} bind () with multiton {tag: String -> Service (instance (), tag)}} val service1: Service = kodein.with ("myTag"). מופע () val service2: Service = kodein.with ("myTag"). מופע () assertThat (service1) .isSameAs (service2)

4.5. ספק

זהו אי-ויכוח בית חרושת כריכה:

val kodein = Kodein {bind () עם הספק {MongoDao ()}} val dao1: Dao = kodein.instance () val dao2: Dao = kodein.instance () assertThat (dao1) .isNotSameAs (dao2)

4.6. למשל

אנחנו יכולים רשום מופע שעועית שהוגדר מראש במיכל:

val dao = MongoDao () val kodein = Kodein {bind () עם מופע (dao)} val fromContainer: Dao = kodein.instance () assertThat (dao) .isSameAs (fromContainer)

4.7. תיוג

אנחנו יכולים גם לרשום יותר מפול אחד מאותו סוג תחת תגים שונים:

val kodein = Kodein {bind ("dao1") עם singleton {MongoDao ()} bind ("dao2") עם singleton {MongoDao ()}} val dao1: Dao = kodein.instance ("dao1") val dao2: Dao = kodein.instance ("dao2") assertThat (dao1) .isNotSameAs (dao2)

4.8. קָבוּעַ

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

val kodein = Kodein {constant ("magic") with 42} val fromContainer: Int = kodein.instance ("magic") assertThat (fromContainer) .isEqualTo (42)

5. הפרדת כריכות

Kodein מאפשר לנו להגדיר שעועית בבלוקים נפרדים ולשלב אותם.

5.1. מודולים

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

val jdbcModule = Kodein.Module {bind () with singleton {JdbcDao ()}} val codein = Kodein {import (jdbcModule) bind () with singleton {Controller (instance ())} bind () with singleton {Service (instance ( ), "myService")}} val dao: Dao = kodein.instance () assertThat (dao) .isInstanceOf (JdbcDao :: class.java)

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

5.2. הרכב

אנו יכולים להרחיב מופע אחד של Kodein מאחר - זה מאפשר לנו להשתמש מחדש בשעועית:

val persistenceContainer = Kodein {bind () עם יחיד {MongoDao ()}} val serviceContainer = Kodein {ext (persistenceContainer) bind () עם singleton {Service (מופע (), "myService")}} val fromPersistence: Dao = persistenceContainer מופע () val fromService: Dao = serviceContainer.instance () assertThat (fromPersistence) .isSameAs (fromService)

5.3. שׁוֹלֵט

אנו יכולים לעקוף כריכות - זה יכול להיות שימושי לבדיקה:

class InMemoryDao: Dao val commonModule = Kodein.Module {bind () with singleton {MongoDao ()} bind () with singleton {Service (instance (), "myService")}} val testContainer = Kodein {import (commonModule) bind ( עוקף = נכון) עם סינגלטון {InMemoryDao ()}} val dao: Dao = testContainer.instance () assertThat (dao) .isInstanceOf (InMemoryDao :: class.java)

6. רב כריכות

אנחנו יכולים להגדיר יותר משעועית אחת עם אותו סוג נפוץ (סופר) במיכל:

val kodein = Kodein {bind () from setBinding () bind (). inSet () with singleton {MongoDao ()} bind (). inSet () with singleton {JdbcDao ()}} val daos: Set = kodein.instance ( ) assertThat (daos.map {it.javaClass as Class}) .containsOnly (MongoDao :: class.java, JdbcDao :: class.java)

7. מזרק

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

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

class Controller2 {מזרק שווי פרטי = KodeinInjector () שירות שירות: שירות על ידי injector.instance () fun injectDependencies (קודin: Kodein) = injector.inject (kodein)} val codein = Kodein {bind () with singleton {MongoDao ()} לאגד () עם סינגלטון {Service (מופע (), "myService")}} בקר בקר = Controller2 () controller.injectDependencies (קודאין) assertThat (controller.service).

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

8. שימוש בקודין עם אנדרואיד

ב- Android, מיכל Kodein מוגדר בהתאמה אישית יישום בכיתה, ובהמשך, היא קשורה ל הֶקשֵׁר למשל. ההנחה היא שכל הרכיבים (פעילויות, שברים, שירותים, מקלטי שידור) מורחבים משיעורי השירות כמו קודאין פעילות ו KodeinFragment:

class MyActivity: Activity (), KodeinInjected {override val injector = KodeinInjector () val random: אקראי לפי מופע () עקיפת fun onCreate (savedInstanceState: Bundle?) {inject (appKodein ())}}

9. ניתוח

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

9.1. מסגרת האביב

מסגרת האביב עשירה בתכונות הרבה יותר מקודיין. לדוגמא, באביב יש מאוד מתקן סריקת רכיבים נוח. כאשר אנו מסמנים את השיעורים שלנו בהערות מסוימות כמו @רְכִיב, @שֵׁרוּת, ו @Named, סריקת הרכיבים אוספת את המחלקות האלה באופן אוטומטי במהלך אתחול המכולה.

גם לאביב יש נקודות הרחבה עוצמתיות למטא-תכנות, מעבד BeanPost ו BeanFactoryPostProcessor, שעשוי להיות קריטי בעת התאמת יישום מוגדר לסביבה מסוימת.

לבסוף, אביב מספק כמה טכנולוגיות נוחות שנבנו על גבי זה, כולל AOP, Transactions, Test Framework, ועוד רבים אחרים. אם אנו רוצים להשתמש באלה, כדאי להישאר עם מיכל ה- IOC של Spring.

9.2. פגיון 2

מסגרת פגיון 2 היא לא עשיר בתכונות כמו Spring Framework, אך הוא פופולרי בפיתוח אנדרואיד בשל מהירותו (הוא מייצר קוד Java שמבצע את ההזרקה ופשוט מבצע אותו בזמן ריצה) וגודלו.

בואו ונשווה בין ספירות וגדלים של שיטות הספריות:

קודיין:שים לב שה- קוטלין-סטדליב תלות מהווה את עיקר המספרים הללו. כאשר אנו לא כוללים את זה, אנו מקבלים 1282 שיטות וגודל DEX בגודל 244 KB.

פגיון 2:

אנו יכולים לראות שמסגרת ה- Dagger 2 מוסיפה הרבה פחות שיטות וקובץ ה- JAR שלה קטן יותר.

לגבי השימוש - זה דומה מאוד בכך שקוד המשתמש מגדיר תלות (דרך מַזרֵק בהערות Kodein ו- JSR-330 ב- Dagger 2) ובהמשך מזריק אותן באמצעות שיחת שיטה אחת.

עם זאת, מאפיין מרכזי של פגיון 2 הוא שהוא מאמת את גרף התלות בזמן הקומפילציה, כך שהוא לא יאפשר ליישום להתקבץ אם יש שגיאת תצורה.

10. מסקנה

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

כמו תמיד, ניתן למצוא את קוד המקור של הדוגמאות לעיל ב- GitHub.


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