Jair Israel Avilés Eusebio
jairaviles.mx
@yajairo87
https://github.com/JairAviles
Marzo 2018
class Player{
fun throwDice(): Int {
val r = Random()
return r.nextInt(5) + 1
}
// do something else
}
class PlayerDI(private val r: Random) {
fun throwDice(): Int {
return.nextInt(5) + 1
}
// do something else
}
Sin inyección de dependencias
Con inyección de dependencias
Logger
Controller
Service
DataSource
Cache
DataParser
ErrorTracker
External
API
Controller
Service
DataSource
DataSource
ErrorTracker
External API
Logger
DataParser
Aplication
Controller A
Controller B
Controller N
Cadena
de Dependencias
Cadena
de Dependencias
Cadena
de Dependencias
...
¿Quién es responsable de construir ese grafo de objetos?
Usualmente la aplicación por si misma
arranca con las dependencias en el momento de lanzamiento de la aplicación
(No es lo mismo pero estan relacionados)
Con inyección de dependencias e
inversión de control
interface Dice{
fun throw(): Int
}
class PlayerDIP(private val dice: Dice) {
fun throwDice(): Int {
return dice.throw()
}
// do something else
}
Aplication
Instancia de
Factories
Controller
Dice
Cadena de
Dependencias
Factory.createDice()
http://kodein.org/
Infix Functions
enum class ZodiacSign {
ARIES, TAURUS, GEMINI, CANCER, LEO, VIRGO, LIBRA, SCORPIO,
SAGITTARIUS, CAPRICORN, AQUARIUS, PISCES
}
enum class Saint {
MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, SHAKA,
DOHKO, MILO, AIOROS, SHURA, CAMUS, AFRODITA
}
data class GoldenSaint(val saint: Saint, val zodiacSign: ZodiacSign)
Invoco a Shaka de Virgo
val virgoGoldenSaint = GoldenSaint(Saint.SHAKA, ZodiacSign.VIRGO)
Infix Functions (cont...)
enum class Saint {
MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, SHAKA, DOHKO,
MILO, AIOROS, SHURA, CAMUS, AFRODITA;
fun of(zodiacSign: ZodiacSign) = GoldenSaint(this, zodiacSign)
}
val sagittariusGoldenSaint = Saint.AIOROS.of(ZodiacSign.SAGITTARIUS)
Invoco a Aioros de Sagitario
enum class Saint {
MU, ALDEBARAN, SAGA, KANON, DEATHMASK, AIORIA, SHAKA, DOHKO,
MILO, AIOROS, SHURA, CAMUS, AFRODITA;
infix fun of(zodiacSign: ZodiacSign) = GoldenSaint(this, zodiacSign)
}
val sagittariusGoldenSaint = AIOROS of SAGITTARIUS
Reified Generics
//El siguiente codigo generaria error, la JVM no tiene noción del tipo T (type erasure)
fun <T> instance() {
//la JVM veria esto como any y no conseguiria definir el tipo T
container.getInstance(T::class.java)
}
//La solución son los Reified types en conjunto con una inline function
inline fun <reified T> instance() {
container.getInstance(T::class.java)
}
val m1 = instance<Manager>()
val m2 : Manager = instance() // Type inference!
Semántica en Kodein
object Injector {
// Definición del grafo de objetos
val kodein = Kodein.lazy {
/*** Simple Bindings ***/
//Define una dependencia singleton que se inicializa de forma Lazy
bind<Gson()> with singleton { Gson() }
bind<Dao>() with singleton { MongoDao() } // Esto es una infix function
bind<OkHttpClient>() with singleton {
OkHttpClient.Builder().build()
}
/*** Factory Bindings ***/
//Define un bloque de dependencias con argumentos
//(nueva instancia cada llamado)
bind<Service>() with factory {
tag: String -> Service(instance(), tag)
}
//Similar al factory, solo que devuelve una unica instancia
bind<Service>() with multiton {
tag: String -> Service(instance(), tag)
}
// ...
}
Semántica en Kodein (cont...)
/*** Dependencia Transitiva ***/
//Define un bloque de dependencias Factory
//sin argumentos (nueva instancia cada llamado)
bind<RestCaller>() with provider {
//Equivalente a usar @Inject - JSR 3330
RestCaller(httpClient = instance(), scheduler = instance(WORKER))
}
/*** Modulos ***/
//Definido en otro lado
val apiModule = Kodein.Module {
bind<Whatever> with singleton { WhateverImpl(instance()) }
}
val kodein = Kodein {
import(apiModule)
}
/*** Binding Tags, es pasado como parametro en instance(MY_TAG) ***/
bind<Scheduler>(UITHREAD) with singleton {
AndroidSchedulers.mainThread()
}
bind<Scheduler>(WORKER) with singleton {
Schedulers.io()
}
companion object {
val WORKER = "worker"
val UITHREAD = "main"
}
Y muchas otras caracteristicas como:
https://github.com/rafakob/KodeinSample