Skip to content

Instantly share code, notes, and snippets.

@emoonadev
Created July 27, 2020 14:56
Show Gist options
  • Save emoonadev/512dbd74bcd507fb7da729c630c27881 to your computer and use it in GitHub Desktop.
Save emoonadev/512dbd74bcd507fb7da729c630c27881 to your computer and use it in GitHub Desktop.
Super simple dependency injection
import kotlin.reflect.KProperty
typealias DependencyContainer = (factory: Container) -> Unit
interface Resolver {
fun <T> resolve(type: Class<T>): T
fun init(apply: DependencyContainer)
}
inline fun <reified T> Resolver.resolve() = resolve(T::class.java)
class DependencyFactory {
enum class InstanceType {
SINGLE, NEW
}
companion object {
var container: Resolver = DependencyInjector()
}
}
interface Container {
fun <T> register(clazz: Class<T>, instanceType: DependencyFactory.InstanceType = DependencyFactory.InstanceType.NEW, apply: (Resolver) -> T)
}
inline fun <reified T> Container.register(instanceType: DependencyFactory.InstanceType = DependencyFactory.InstanceType.NEW, noinline apply: (Resolver) -> T) {
register(T::class.java, instanceType, apply)
}
class DependencyInjector : Resolver, Container {
private var services = HashMap<String, () -> Any>()
private var uniqueInstanceServices = HashMap<String, Any>()
override fun init(apply: DependencyContainer) {
apply(this)
}
override fun <T> register(clazz: Class<T>, instanceType: DependencyFactory.InstanceType, apply: (Resolver) -> T) {
val serviceName = clazz.simpleName.guard { return }
if (isExistIn(services = services, key = serviceName) || isExistIn(services = uniqueInstanceServices, key = serviceName)) return
if (instanceType == DependencyFactory.InstanceType.NEW) {
services[serviceName] = { apply(this) } as () -> Any
} else {
uniqueInstanceServices[serviceName] = apply(this) as Any
}
}
private fun <T> isExistIn(services: HashMap<String, T>, key: String?): Boolean {
return services.filterKeys { it == key }.isNotEmpty()
}
override fun <T> resolve(type: Class<T>): T {
val serviceName = type.simpleName
val service = (services[serviceName]?.invoke() ?: uniqueInstanceServices[serviceName])
return service as T
}
}
inline fun <reified T> resolve() = Resolving(T::class.java)
class Resolving<T>(private var service: Class<T>) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return DependencyFactory.container.resolve(service)
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Class<T>) {
service = value
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment