Created
July 27, 2020 14:56
-
-
Save emoonadev/512dbd74bcd507fb7da729c630c27881 to your computer and use it in GitHub Desktop.
Super simple dependency injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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